Merge branch 'cli' into date2
Conflicts: pom.xml
1
pom.xml
|
@ -78,6 +78,7 @@
|
|||
<module>teavm-html4j</module>
|
||||
<module>teavm-samples</module>
|
||||
<module>teavm-platform</module>
|
||||
<module>teavm-cli</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
4
teavm-cli/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
/.settings
|
||||
/.classpath
|
||||
/.project
|
55
teavm-cli/pom.xml
Normal file
|
@ -0,0 +1,55 @@
|
|||
<!--
|
||||
Copyright 2014 Alexey Andreev.
|
||||
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm</artifactId>
|
||||
<version>0.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>teavm-cli</artifactId>
|
||||
|
||||
<name>TeaVM CLI</name>
|
||||
<description>TeaVM command line tools</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.cli;
|
||||
|
||||
import org.teavm.tooling.TeaVMToolLog;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
class ConsoleTeaVMToolLog implements TeaVMToolLog {
|
||||
@Override
|
||||
public void info(String text) {
|
||||
System.out.println("INFO: " + text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text) {
|
||||
System.out.println("DEBUG: " + text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text) {
|
||||
System.out.println("WARNING: " + text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text) {
|
||||
System.out.println("ERROR: " + text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String text, Throwable e) {
|
||||
System.out.println("INFO: " + text);
|
||||
e.printStackTrace(System.out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text, Throwable e) {
|
||||
System.out.println("DEBUG: " + text);
|
||||
e.printStackTrace(System.out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text, Throwable e) {
|
||||
System.out.println("WARNING: " + text);
|
||||
e.printStackTrace(System.out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text, Throwable e) {
|
||||
System.out.println("ERROR: " + text);
|
||||
e.printStackTrace(System.out);
|
||||
}
|
||||
}
|
146
teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.cli;
|
||||
|
||||
import java.io.File;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.teavm.tooling.RuntimeCopyOperation;
|
||||
import org.teavm.tooling.TeaVMTool;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class TeaVMRunner {
|
||||
@SuppressWarnings("static-access")
|
||||
public static void main(String[] args) {
|
||||
Options options = new Options();
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("directory")
|
||||
.hasArg()
|
||||
.withDescription("a directory where to put generated files (current directory by default)")
|
||||
.withLongOpt("targetdir")
|
||||
.create('d'));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("file")
|
||||
.hasArg()
|
||||
.withDescription("a file where to put decompiled classes (classes.js by default)")
|
||||
.withLongOpt("targetfile")
|
||||
.create('f'));
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("causes TeaVM to generate minimized JavaScript file")
|
||||
.withLongOpt("minify")
|
||||
.create("m"));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("separate|merge|none")
|
||||
.hasArg()
|
||||
.withDescription("how to attach runtime. Possible values are: separate|merge|none")
|
||||
.withLongOpt("runtime")
|
||||
.create("r"));
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("causes TeaVM to include default main page")
|
||||
.withLongOpt("mainpage")
|
||||
.create());
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("causes TeaVM to log bytecode")
|
||||
.create("logbytecode"));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("number")
|
||||
.hasArg()
|
||||
.withDescription("how many threads should TeaVM run")
|
||||
.withLongOpt("threads")
|
||||
.create("t"));
|
||||
|
||||
if (args.length == 0) {
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
CommandLineParser parser = new PosixParser();
|
||||
CommandLine commandLine;
|
||||
try {
|
||||
commandLine = parser.parse(options, args);
|
||||
} catch (ParseException e) {
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
TeaVMTool tool = new TeaVMTool();
|
||||
tool.setBytecodeLogging(commandLine.hasOption("logbytecode"));
|
||||
if (commandLine.hasOption("d")) {
|
||||
tool.setTargetDirectory(new File(commandLine.getOptionValue("d")));
|
||||
}
|
||||
if (commandLine.hasOption("f")) {
|
||||
tool.setTargetFileName(commandLine.getOptionValue("f"));
|
||||
}
|
||||
if (commandLine.hasOption("m")) {
|
||||
tool.setMinifying(true);
|
||||
} else {
|
||||
tool.setMinifying(false);
|
||||
}
|
||||
if (commandLine.hasOption("r")) {
|
||||
switch (commandLine.getOptionValue("r")) {
|
||||
case "separate":
|
||||
tool.setRuntime(RuntimeCopyOperation.SEPARATE);
|
||||
break;
|
||||
case "merge":
|
||||
tool.setRuntime(RuntimeCopyOperation.MERGED);
|
||||
break;
|
||||
case "none":
|
||||
tool.setRuntime(RuntimeCopyOperation.NONE);
|
||||
break;
|
||||
default:
|
||||
System.err.println("Wrong parameter for -r option specified");
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (commandLine.hasOption("mainpage")) {
|
||||
tool.setMainPageIncluded(true);
|
||||
}
|
||||
if (commandLine.hasOption("t")) {
|
||||
try {
|
||||
tool.setNumThreads(Integer.parseInt(commandLine.getOptionValue("t")));
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Wrong parameter for -t option specified");
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
args = commandLine.getArgs();
|
||||
if (args.length > 1) {
|
||||
System.err.println("Unexpected arguments");
|
||||
printUsage(options);
|
||||
return;
|
||||
} else if (args.length == 1) {
|
||||
tool.setMainClass(args[0]);
|
||||
}
|
||||
tool.setLog(new ConsoleTeaVMToolLog());
|
||||
tool.getProperties().putAll(System.getProperties());
|
||||
|
||||
try {
|
||||
tool.generate();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void printUsage(Options options) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("java " + TeaVMRunner.class.getName() + " [OPTIONS] [qualified.main.Class]", options);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
183
teavm-cli/src/main/java/org/teavm/cli/TeaVMTestRunner.java
Normal file
|
@ -0,0 +1,183 @@
|
|||
package org.teavm.cli;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.testing.TestAdapter;
|
||||
import org.teavm.tooling.TeaVMTestTool;
|
||||
import org.teavm.tooling.TeaVMToolException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class TeaVMTestRunner {
|
||||
@SuppressWarnings("static-access")
|
||||
public static void main(String[] args) {
|
||||
Options options = new Options();
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("directory")
|
||||
.hasArg()
|
||||
.withDescription("a directory where to put generated files (current directory by default)")
|
||||
.withLongOpt("targetdir")
|
||||
.create('d'));
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("causes TeaVM to generate minimized JavaScript file")
|
||||
.withLongOpt("minify")
|
||||
.create("m"));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("number")
|
||||
.hasArg()
|
||||
.withDescription("how many threads should TeaVM run")
|
||||
.withLongOpt("threads")
|
||||
.create("t"));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("class name")
|
||||
.hasArg()
|
||||
.withDescription("qualified class name of test adapter")
|
||||
.withLongOpt("adapter")
|
||||
.create("a"));
|
||||
options.addOption(OptionBuilder
|
||||
.hasArg()
|
||||
.hasOptionalArgs()
|
||||
.withArgName("class name")
|
||||
.withDescription("qualified class names of transformers")
|
||||
.withLongOpt("transformers")
|
||||
.create("T"));
|
||||
|
||||
if (args.length == 0) {
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
CommandLineParser parser = new PosixParser();
|
||||
CommandLine commandLine;
|
||||
try {
|
||||
commandLine = parser.parse(options, args);
|
||||
} catch (ParseException e) {
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
TeaVMTestTool tool = new TeaVMTestTool();
|
||||
tool.setOutputDir(new File(commandLine.getOptionValue("d", ".")));
|
||||
tool.setMinifying(commandLine.hasOption("m"));
|
||||
try {
|
||||
tool.setNumThreads(Integer.parseInt(commandLine.getOptionValue("t", "1")));
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Invalid number specified for -t option");
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
if (commandLine.hasOption("a")) {
|
||||
tool.setAdapter(instantiateAdapter(commandLine.getOptionValue("a")));
|
||||
}
|
||||
if (commandLine.hasOption("T")) {
|
||||
for (String transformerType : commandLine.getOptionValues("T")) {
|
||||
tool.getTransformers().add(instantiateTransformer(transformerType));
|
||||
}
|
||||
}
|
||||
args = commandLine.getArgs();
|
||||
if (args.length == 0) {
|
||||
System.err.println("You did not specify any test classes");
|
||||
printUsage(options);
|
||||
return;
|
||||
}
|
||||
tool.getTestClasses().addAll(Arrays.asList(args));
|
||||
|
||||
tool.setLog(new ConsoleTeaVMToolLog());
|
||||
tool.getProperties().putAll(System.getProperties());
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
tool.generate();
|
||||
} catch (TeaVMToolException e) {
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-2);
|
||||
}
|
||||
System.out.println("Operation took " + (System.currentTimeMillis() - start) + " milliseconds");
|
||||
}
|
||||
|
||||
private static TestAdapter instantiateAdapter(String adapterName) {
|
||||
Class<?> adapterClass;
|
||||
try {
|
||||
adapterClass = Class.forName(adapterName, true, TeaVMTestRunner.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Adapter not found: " + adapterName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
if (!TestAdapter.class.isAssignableFrom(adapterClass)) {
|
||||
System.err.println("Adapter class does not implement TestAdapter: " + adapterName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
Constructor<?> cons;
|
||||
try {
|
||||
cons = adapterClass.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Adapter class does not contain no-arg constructor: " + adapterName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (TestAdapter)cons.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
System.err.println("Error instantiating adapter: " + adapterName);
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("Error instantiating adapter: " + adapterName);
|
||||
e.getTargetException().printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static ClassHolderTransformer instantiateTransformer(String transformerName) {
|
||||
Class<?> adapterClass;
|
||||
try {
|
||||
adapterClass = Class.forName(transformerName, true, TeaVMTestRunner.class.getClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Transformer not found: " + transformerName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
if (!ClassHolderTransformer.class.isAssignableFrom(adapterClass)) {
|
||||
System.err.println("Transformer class does not implement ClassHolderTransformer: " + transformerName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
Constructor<?> cons;
|
||||
try {
|
||||
cons = adapterClass.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Transformer class does not contain no-arg constructor: " + transformerName);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (ClassHolderTransformer)cons.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
System.err.println("Error instantiating transformer: " + transformerName);
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("Error instantiating transformer: " + transformerName);
|
||||
e.getTargetException().printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void printUsage(Options options) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("java " + TeaVMTestRunner.class.getName() + " [OPTIONS] test_name {test_name}", options);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.maven;
|
||||
package org.teavm.tooling;
|
||||
|
||||
/**
|
||||
*
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.tooling;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class EmptyTeaVMToolLog implements TeaVMToolLog {
|
||||
@Override
|
||||
public void info(String text) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String text, Throwable e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text, Throwable e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text, Throwable e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text, Throwable e) {
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.maven;
|
||||
package org.teavm.tooling;
|
||||
|
||||
/**
|
||||
*
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.maven;
|
||||
package org.teavm.tooling;
|
||||
|
||||
/**
|
||||
*
|
359
teavm-core/src/main/java/org/teavm/tooling/TeaVMTestTool.java
Normal file
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.tooling;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.teavm.common.FiniteExecutor;
|
||||
import org.teavm.common.SimpleFiniteExecutor;
|
||||
import org.teavm.common.ThreadPoolFiniteExecutor;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.parsing.ClasspathClassHolderSource;
|
||||
import org.teavm.testing.JUnitTestAdapter;
|
||||
import org.teavm.testing.TestAdapter;
|
||||
import org.teavm.vm.DirectoryBuildTarget;
|
||||
import org.teavm.vm.TeaVM;
|
||||
import org.teavm.vm.TeaVMBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class TeaVMTestTool {
|
||||
private Map<String, List<MethodReference>> groupedMethods = new HashMap<>();
|
||||
private Map<MethodReference, String> fileNames = new HashMap<>();
|
||||
private List<MethodReference> testMethods = new ArrayList<>();
|
||||
private File outputDir = new File(".");
|
||||
private boolean minifying = true;
|
||||
private int numThreads = 1;
|
||||
private TestAdapter adapter = new JUnitTestAdapter();
|
||||
private List<ClassHolderTransformer> transformers = new ArrayList<>();
|
||||
private List<String> additionalScripts = new ArrayList<>();
|
||||
private List<String> additionalScriptLocalPaths = new ArrayList<>();
|
||||
private Properties properties = new Properties();
|
||||
private List<String> testClasses = new ArrayList<>();
|
||||
private ClassLoader classLoader = TeaVMTestTool.class.getClassLoader();
|
||||
private TeaVMToolLog log = new EmptyTeaVMToolLog();
|
||||
|
||||
public File getOutputDir() {
|
||||
return outputDir;
|
||||
}
|
||||
|
||||
public void setOutputDir(File outputDir) {
|
||||
this.outputDir = outputDir;
|
||||
}
|
||||
|
||||
public boolean isMinifying() {
|
||||
return minifying;
|
||||
}
|
||||
|
||||
public void setMinifying(boolean minifying) {
|
||||
this.minifying = minifying;
|
||||
}
|
||||
|
||||
public int getNumThreads() {
|
||||
return numThreads;
|
||||
}
|
||||
|
||||
public void setNumThreads(int numThreads) {
|
||||
this.numThreads = numThreads;
|
||||
}
|
||||
|
||||
public TestAdapter getAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
public void setAdapter(TestAdapter adapter) {
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
public List<ClassHolderTransformer> getTransformers() {
|
||||
return transformers;
|
||||
}
|
||||
|
||||
public List<String> getAdditionalScripts() {
|
||||
return additionalScripts;
|
||||
}
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public List<String> getTestClasses() {
|
||||
return testClasses;
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
public void setClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
public TeaVMToolLog getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
public void setLog(TeaVMToolLog log) {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
public void generate() throws TeaVMToolException {
|
||||
Runnable finalizer = null;
|
||||
try {
|
||||
new File(outputDir, "tests").mkdirs();
|
||||
new File(outputDir, "res").mkdirs();
|
||||
resourceToFile("org/teavm/javascript/runtime.js", "res/runtime.js");
|
||||
String prefix = "org/teavm/tooling/test";
|
||||
resourceToFile(prefix + "/res/junit-support.js", "res/junit-support.js");
|
||||
resourceToFile(prefix + "/res/junit.css", "res/junit.css");
|
||||
resourceToFile(prefix + "/res/class_obj.png", "res/class_obj.png");
|
||||
resourceToFile(prefix + "/res/control-000-small.png", "res/control-000-small.png");
|
||||
resourceToFile(prefix + "/res/methpub_obj.png", "res/methpub_obj.png");
|
||||
resourceToFile(prefix + "/res/package_obj.png", "res/package_obj.png");
|
||||
resourceToFile(prefix + "/res/tick-small-red.png", "res/tick-small-red.png");
|
||||
resourceToFile(prefix + "/res/tick-small.png", "res/tick-small.png");
|
||||
resourceToFile(prefix + "/res/toggle-small-expand.png", "res/toggle-small-expand.png");
|
||||
resourceToFile(prefix + "/res/toggle-small.png", "res/toggle-small.png");
|
||||
resourceToFile(prefix + "/junit.html", "junit.html");
|
||||
final ClassHolderSource classSource = new ClasspathClassHolderSource(classLoader);
|
||||
for (String testClass : testClasses) {
|
||||
ClassHolder classHolder = classSource.get(testClass);
|
||||
if (classHolder == null) {
|
||||
throw new TeaVMToolException("Could not find class " + testClass);
|
||||
}
|
||||
findTests(classHolder);
|
||||
}
|
||||
|
||||
includeAdditionalScripts(classLoader);
|
||||
File allTestsFile = new File(outputDir, "tests/all.js");
|
||||
try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) {
|
||||
allTestsWriter.write("prepare = function() {\n");
|
||||
allTestsWriter.write(" return new JUnitServer(document.body).readTests([");
|
||||
boolean first = true;
|
||||
for (String testClass : testClasses) {
|
||||
Collection<MethodReference> methods = groupedMethods.get(testClass);
|
||||
if (methods == null) {
|
||||
continue;
|
||||
}
|
||||
if (!first) {
|
||||
allTestsWriter.append(",");
|
||||
}
|
||||
first = false;
|
||||
allTestsWriter.append("\n { name : \"").append(testClass).append("\", methods : [");
|
||||
boolean firstMethod = true;
|
||||
for (MethodReference methodRef : methods) {
|
||||
String scriptName = "tests/" + fileNames.size() + ".js";
|
||||
fileNames.put(methodRef, scriptName);
|
||||
if (!firstMethod) {
|
||||
allTestsWriter.append(",");
|
||||
}
|
||||
firstMethod = false;
|
||||
allTestsWriter.append("\n { name : \"" + methodRef.getName() + "\", script : \"" +
|
||||
scriptName + "\", expected : [");
|
||||
MethodHolder methodHolder = classSource.get(testClass).getMethod(
|
||||
methodRef.getDescriptor());
|
||||
boolean firstException = true;
|
||||
for (String exception : adapter.getExpectedExceptions(methodHolder)) {
|
||||
if (!firstException) {
|
||||
allTestsWriter.append(", ");
|
||||
}
|
||||
firstException = false;
|
||||
allTestsWriter.append("\"" + exception + "\"");
|
||||
}
|
||||
allTestsWriter.append("], additionalScripts : [");
|
||||
for (int i = 0; i < additionalScriptLocalPaths.size(); ++i) {
|
||||
if (i > 0) {
|
||||
allTestsWriter.append(", ");
|
||||
}
|
||||
escapeString(additionalScriptLocalPaths.get(i), allTestsWriter);
|
||||
}
|
||||
allTestsWriter.append("] }");
|
||||
}
|
||||
allTestsWriter.append("] }");
|
||||
}
|
||||
allTestsWriter.write("], function() {}); }");
|
||||
}
|
||||
int methodsGenerated = 0;
|
||||
log.info("Generating test files");
|
||||
FiniteExecutor executor = new SimpleFiniteExecutor();
|
||||
if (numThreads != 1) {
|
||||
int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors();
|
||||
final ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads);
|
||||
finalizer = new Runnable() {
|
||||
@Override public void run() {
|
||||
threadedExecutor.stop();
|
||||
}
|
||||
};
|
||||
executor = threadedExecutor;
|
||||
}
|
||||
for (final MethodReference method : testMethods) {
|
||||
executor.execute(new Runnable() {
|
||||
@Override public void run() {
|
||||
log.debug("Building test for " + method);
|
||||
try {
|
||||
decompileClassesForTest(classLoader, new CopyClassHolderSource(classSource), method,
|
||||
fileNames.get(method), new SimpleFiniteExecutor());
|
||||
} catch (IOException e) {
|
||||
log.error("Error generating JavaScript", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
++methodsGenerated;
|
||||
}
|
||||
executor.complete();
|
||||
log.info("Test files successfully generated for " + methodsGenerated + " method(s).");
|
||||
} catch (IOException e) {
|
||||
throw new TeaVMToolException("IO error occured generating JavaScript files", e);
|
||||
} finally {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resourceToFile(String resource, String fileName) throws IOException {
|
||||
try (InputStream input = TeaVMTestTool.class.getClassLoader().getResourceAsStream(resource)) {
|
||||
try (OutputStream output = new FileOutputStream(new File(outputDir, fileName))) {
|
||||
IOUtils.copy(input, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findTests(ClassHolder cls) {
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
if (adapter.acceptMethod(method)) {
|
||||
MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor());
|
||||
testMethods.add(ref);
|
||||
List<MethodReference> group = groupedMethods.get(cls.getName());
|
||||
if (group == null) {
|
||||
group = new ArrayList<>();
|
||||
groupedMethods.put(cls.getName(), group);
|
||||
}
|
||||
group.add(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void includeAdditionalScripts(ClassLoader classLoader) throws TeaVMToolException {
|
||||
if (additionalScripts == null) {
|
||||
return;
|
||||
}
|
||||
for (String script : additionalScripts) {
|
||||
String simpleName = script.substring(script.lastIndexOf('/') + 1);
|
||||
additionalScriptLocalPaths.add("tests/" + simpleName);
|
||||
if (classLoader.getResource(script) == null) {
|
||||
throw new TeaVMToolException("Additional script " + script + " was not found");
|
||||
}
|
||||
File file = new File(outputDir, "tests/" + simpleName);
|
||||
try (InputStream in = classLoader.getResourceAsStream(script)) {
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
try(OutputStream out = new FileOutputStream(file)) {
|
||||
IOUtils.copy(in, out);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new TeaVMToolException("Error copying additional script " + script, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource,
|
||||
MethodReference methodRef, String targetName, FiniteExecutor executor) throws IOException {
|
||||
TeaVM vm = new TeaVMBuilder()
|
||||
.setClassLoader(classLoader)
|
||||
.setClassSource(classSource)
|
||||
.setExecutor(executor)
|
||||
.build();
|
||||
vm.setProperties(properties);
|
||||
vm.setMinifying(minifying);
|
||||
vm.installPlugins();
|
||||
new TestExceptionPlugin().install(vm);
|
||||
for (ClassHolderTransformer transformer : transformers) {
|
||||
vm.add(transformer);
|
||||
}
|
||||
File file = new File(outputDir, targetName);
|
||||
try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
|
||||
MethodReference cons = new MethodReference(methodRef.getClassName(),
|
||||
new MethodDescriptor("<init>", ValueType.VOID));
|
||||
MethodReference exceptionMsg = new MethodReference("java.lang.Throwable", "getMessage",
|
||||
ValueType.object("java.lang.String"));
|
||||
vm.entryPoint("initInstance", cons);
|
||||
vm.entryPoint("runTest", methodRef).withValue(0, cons.getClassName());
|
||||
vm.entryPoint("extractException", exceptionMsg);
|
||||
vm.exportType("TestClass", cons.getClassName());
|
||||
vm.build(innerWriter, new DirectoryBuildTarget(outputDir));
|
||||
if (!vm.hasMissingItems()) {
|
||||
innerWriter.append("\n");
|
||||
innerWriter.append("\nJUnitClient.run();");
|
||||
innerWriter.close();
|
||||
} else {
|
||||
innerWriter.append("JUnitClient.reportError(\n");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
vm.showMissingItems(sb);
|
||||
escapeStringLiteral(sb.toString(), innerWriter);
|
||||
innerWriter.append(");");
|
||||
log.warning("Error building test " + methodRef);
|
||||
log.warning(sb.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void escapeStringLiteral(String text, Writer writer) throws IOException {
|
||||
int index = 0;
|
||||
while (true) {
|
||||
int next = text.indexOf('\n', index);
|
||||
if (next < 0) {
|
||||
break;
|
||||
}
|
||||
escapeString(text.substring(index, next + 1), writer);
|
||||
writer.append(" +\n");
|
||||
index = next + 1;
|
||||
}
|
||||
escapeString(text.substring(index), writer);
|
||||
}
|
||||
|
||||
private void escapeString(String string, Writer writer) throws IOException {
|
||||
writer.append('\"');
|
||||
for (int i = 0; i < string.length(); ++i) {
|
||||
char c = string.charAt(i);
|
||||
switch (c) {
|
||||
case '"':
|
||||
writer.append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
writer.append("\\\\");
|
||||
break;
|
||||
case '\n':
|
||||
writer.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
writer.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
writer.append("\\t");
|
||||
break;
|
||||
default:
|
||||
writer.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
writer.append('\"');
|
||||
}
|
||||
}
|
256
teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.tooling;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.teavm.common.ThreadPoolFiniteExecutor;
|
||||
import org.teavm.javascript.RenderingContext;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.parsing.ClasspathClassHolderSource;
|
||||
import org.teavm.vm.*;
|
||||
import org.teavm.vm.spi.AbstractRendererListener;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class TeaVMTool {
|
||||
private File targetDirectory = new File(".");
|
||||
private String targetFileName = "classes.js";
|
||||
private boolean minifying = true;
|
||||
private String mainClass;
|
||||
private RuntimeCopyOperation runtime = RuntimeCopyOperation.SEPARATE;
|
||||
private Properties properties = new Properties();
|
||||
private boolean mainPageIncluded;
|
||||
private boolean bytecodeLogging;
|
||||
private int numThreads = 1;
|
||||
private List<ClassHolderTransformer> transformers = new ArrayList<>();
|
||||
private List<ClassAlias> classAliases = new ArrayList<>();
|
||||
private List<MethodAlias> methodAliases = new ArrayList<>();
|
||||
private TeaVMToolLog log = new EmptyTeaVMToolLog();
|
||||
private ClassLoader classLoader = TeaVMTool.class.getClassLoader();
|
||||
|
||||
public File getTargetDirectory() {
|
||||
return targetDirectory;
|
||||
}
|
||||
|
||||
public void setTargetDirectory(File targetDirectory) {
|
||||
this.targetDirectory = targetDirectory;
|
||||
}
|
||||
|
||||
public String getTargetFileName() {
|
||||
return targetFileName;
|
||||
}
|
||||
|
||||
public void setTargetFileName(String targetFileName) {
|
||||
this.targetFileName = targetFileName;
|
||||
}
|
||||
|
||||
public boolean isMinifying() {
|
||||
return minifying;
|
||||
}
|
||||
|
||||
public void setMinifying(boolean minifying) {
|
||||
this.minifying = minifying;
|
||||
}
|
||||
|
||||
public String getMainClass() {
|
||||
return mainClass;
|
||||
}
|
||||
|
||||
public void setMainClass(String mainClass) {
|
||||
this.mainClass = mainClass;
|
||||
}
|
||||
|
||||
public RuntimeCopyOperation getRuntime() {
|
||||
return runtime;
|
||||
}
|
||||
|
||||
public void setRuntime(RuntimeCopyOperation runtime) {
|
||||
this.runtime = runtime;
|
||||
}
|
||||
|
||||
public boolean isMainPageIncluded() {
|
||||
return mainPageIncluded;
|
||||
}
|
||||
|
||||
public void setMainPageIncluded(boolean mainPageIncluded) {
|
||||
this.mainPageIncluded = mainPageIncluded;
|
||||
}
|
||||
|
||||
public boolean isBytecodeLogging() {
|
||||
return bytecodeLogging;
|
||||
}
|
||||
|
||||
public void setBytecodeLogging(boolean bytecodeLogging) {
|
||||
this.bytecodeLogging = bytecodeLogging;
|
||||
}
|
||||
|
||||
public int getNumThreads() {
|
||||
return numThreads;
|
||||
}
|
||||
|
||||
public void setNumThreads(int numThreads) {
|
||||
this.numThreads = numThreads;
|
||||
}
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public List<ClassHolderTransformer> getTransformers() {
|
||||
return transformers;
|
||||
}
|
||||
|
||||
public List<ClassAlias> getClassAliases() {
|
||||
return classAliases;
|
||||
}
|
||||
|
||||
public List<MethodAlias> getMethodAliases() {
|
||||
return methodAliases;
|
||||
}
|
||||
|
||||
public TeaVMToolLog getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
public void setLog(TeaVMToolLog log) {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
public void setClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
public void generate() throws TeaVMToolException {
|
||||
Runnable finalizer = null;
|
||||
try {
|
||||
log.info("Building JavaScript file");
|
||||
TeaVMBuilder vmBuilder = new TeaVMBuilder();
|
||||
vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader));
|
||||
if (numThreads != 1) {
|
||||
int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors();
|
||||
final ThreadPoolFiniteExecutor executor = new ThreadPoolFiniteExecutor(threads);
|
||||
finalizer = new Runnable() {
|
||||
@Override public void run() {
|
||||
executor.stop();
|
||||
}
|
||||
};
|
||||
vmBuilder.setExecutor(executor);
|
||||
}
|
||||
TeaVM vm = vmBuilder.build();
|
||||
vm.setMinifying(minifying);
|
||||
vm.setBytecodeLogging(bytecodeLogging);
|
||||
vm.setProperties(properties);
|
||||
vm.installPlugins();
|
||||
for (ClassHolderTransformer transformer : transformers) {
|
||||
vm.add(transformer);
|
||||
}
|
||||
if (mainClass != null) {
|
||||
MethodDescriptor mainMethodDesc = new MethodDescriptor("main", ValueType.arrayOf(
|
||||
ValueType.object("java.lang.String")), ValueType.VOID);
|
||||
vm.entryPoint("main", new MethodReference(mainClass, mainMethodDesc))
|
||||
.withValue(1, "java.lang.String");
|
||||
}
|
||||
for (ClassAlias alias : classAliases) {
|
||||
vm.exportType(alias.getAlias(), alias.getClassName());
|
||||
}
|
||||
for (MethodAlias methodAlias : methodAliases) {
|
||||
MethodReference ref = new MethodReference(methodAlias.getClassName(), methodAlias.getMethodName(),
|
||||
MethodDescriptor.parseSignature(methodAlias.getDescriptor()));
|
||||
TeaVMEntryPoint entryPoint = vm.entryPoint(methodAlias.getAlias(), ref);
|
||||
if (methodAlias.getTypes() != null) {
|
||||
for (int i = 0; i < methodAlias.getTypes().length; ++i) {
|
||||
String types = methodAlias.getTypes()[i];
|
||||
if (types != null) {
|
||||
for (String type : types.split(" +")) {
|
||||
type = type.trim();
|
||||
if (!type.isEmpty()) {
|
||||
entryPoint.withValue(i, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
targetDirectory.mkdirs();
|
||||
try (FileWriter writer = new FileWriter(new File(targetDirectory, targetFileName))) {
|
||||
if (runtime == RuntimeCopyOperation.MERGED) {
|
||||
vm.add(runtimeInjector);
|
||||
}
|
||||
vm.build(writer, new DirectoryBuildTarget(targetDirectory));
|
||||
vm.checkForMissingItems();
|
||||
log.info("JavaScript file successfully built");
|
||||
}
|
||||
if (runtime == RuntimeCopyOperation.SEPARATE) {
|
||||
resourceToFile("org/teavm/javascript/runtime.js", "runtime.js");
|
||||
}
|
||||
if (mainPageIncluded) {
|
||||
String text;
|
||||
try (Reader reader = new InputStreamReader(classLoader.getResourceAsStream(
|
||||
"org/teavm/tooling/main.html"), "UTF-8")) {
|
||||
text = IOUtils.toString(reader).replace("${classes.js}", targetFileName);
|
||||
}
|
||||
File mainPageFile = new File(targetDirectory, "main.html");
|
||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(mainPageFile), "UTF-8")) {
|
||||
writer.append(text);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new TeaVMToolException("IO error occured", e);
|
||||
} finally {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractRendererListener runtimeInjector = new AbstractRendererListener() {
|
||||
@Override
|
||||
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException {
|
||||
@SuppressWarnings("resource")
|
||||
StringWriter writer = new StringWriter();
|
||||
resourceToWriter("org/teavm/javascript/runtime.js", writer);
|
||||
writer.close();
|
||||
context.getWriter().append(writer.toString()).newLine();
|
||||
}
|
||||
};
|
||||
|
||||
private void resourceToFile(String resource, String fileName) throws IOException {
|
||||
try (InputStream input = TeaVMTool.class.getClassLoader().getResourceAsStream(resource)) {
|
||||
try (OutputStream output = new FileOutputStream(new File(targetDirectory, fileName))) {
|
||||
IOUtils.copy(input, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resourceToWriter(String resource, Writer writer) throws IOException {
|
||||
try (InputStream input = TeaVMTool.class.getClassLoader().getResourceAsStream(resource)) {
|
||||
IOUtils.copy(input, writer, "UTF-8");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.tooling;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class TeaVMToolException extends Exception {
|
||||
private static final long serialVersionUID = 579149191624783241L;
|
||||
|
||||
public TeaVMToolException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public TeaVMToolException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TeaVMToolException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
38
teavm-core/src/main/java/org/teavm/tooling/TeaVMToolLog.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.tooling;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface TeaVMToolLog {
|
||||
void info(String text);
|
||||
|
||||
void debug(String text);
|
||||
|
||||
void warning(String text);
|
||||
|
||||
void error(String text);
|
||||
|
||||
void info(String text, Throwable e);
|
||||
|
||||
void debug(String text, Throwable e);
|
||||
|
||||
void warning(String text, Throwable e);
|
||||
|
||||
void error(String text, Throwable e);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.tooling;
|
||||
|
||||
import org.teavm.dependency.*;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class TestExceptionDependency implements DependencyListener {
|
||||
private MethodReference getMessageRef = new MethodReference("java.lang.Throwable", "getMessage",
|
||||
ValueType.object("java.lang.String"));
|
||||
private DependencyNode allClasses;
|
||||
|
||||
@Override
|
||||
public void started(DependencyAgent agent) {
|
||||
allClasses = agent.createNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyAgent agent, String className) {
|
||||
if (isException(agent.getClassSource(), className)) {
|
||||
allClasses.propagate(className);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isException(ClassReaderSource classSource, String className) {
|
||||
while (className != null) {
|
||||
if (className.equals("java.lang.Throwable")) {
|
||||
return true;
|
||||
}
|
||||
ClassReader cls = classSource.get(className);
|
||||
if (cls == null) {
|
||||
return false;
|
||||
}
|
||||
className = cls.getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method) {
|
||||
if (method.getReference().equals(getMessageRef)) {
|
||||
allClasses.connect(method.getVariable(0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyAgent agent, FieldDependency field) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* 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.teavm.tooling;
|
||||
|
||||
import org.teavm.vm.spi.TeaVMHost;
|
||||
import org.teavm.vm.spi.TeaVMPlugin;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class TestExceptionPlugin implements TeaVMPlugin {
|
||||
@Override
|
||||
public void install(TeaVMHost host) {
|
||||
host.add(new TestExceptionDependency());
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 774 B After Width: | Height: | Size: 774 B |
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 297 B |
Before Width: | Height: | Size: 325 B After Width: | Height: | Size: 325 B |
Before Width: | Height: | Size: 345 B After Width: | Height: | Size: 345 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
Before Width: | Height: | Size: 394 B After Width: | Height: | Size: 394 B |
|
@ -15,14 +15,13 @@
|
|||
*/
|
||||
package org.teavm.maven;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
|
@ -32,15 +31,8 @@ import org.apache.maven.plugins.annotations.Mojo;
|
|||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.teavm.common.ThreadPoolFiniteExecutor;
|
||||
import org.teavm.javascript.RenderingContext;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.parsing.ClasspathClassHolderSource;
|
||||
import org.teavm.vm.*;
|
||||
import org.teavm.vm.spi.AbstractRendererListener;
|
||||
import org.teavm.tooling.*;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -94,6 +86,8 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
@Parameter
|
||||
private MethodAlias[] methodAliases;
|
||||
|
||||
private TeaVMTool tool = new TeaVMTool();
|
||||
|
||||
public void setProject(MavenProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
@ -153,105 +147,35 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
@Override
|
||||
public void execute() throws MojoExecutionException {
|
||||
Log log = getLog();
|
||||
Runnable finalizer = null;
|
||||
tool.setLog(new MavenTeaVMToolLog(log));
|
||||
try {
|
||||
ClassLoader classLoader = prepareClassLoader();
|
||||
log.info("Building JavaScript file");
|
||||
TeaVMBuilder vmBuilder = new TeaVMBuilder();
|
||||
vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader));
|
||||
if (numThreads != 1) {
|
||||
int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors();
|
||||
final ThreadPoolFiniteExecutor executor = new ThreadPoolFiniteExecutor(threads);
|
||||
finalizer = new Runnable() {
|
||||
@Override public void run() {
|
||||
executor.stop();
|
||||
}
|
||||
};
|
||||
vmBuilder.setExecutor(executor);
|
||||
}
|
||||
TeaVM vm = vmBuilder.build();
|
||||
vm.setMinifying(minifying);
|
||||
vm.setBytecodeLogging(bytecodeLogging);
|
||||
vm.setProperties(properties);
|
||||
vm.installPlugins();
|
||||
for (ClassHolderTransformer transformer : instantiateTransformers(classLoader)) {
|
||||
vm.add(transformer);
|
||||
}
|
||||
if (mainClass != null) {
|
||||
MethodDescriptor mainMethodDesc = new MethodDescriptor("main", ValueType.arrayOf(
|
||||
ValueType.object("java.lang.String")), ValueType.VOID);
|
||||
vm.entryPoint("main", new MethodReference(mainClass, mainMethodDesc))
|
||||
.withValue(1, "java.lang.String");
|
||||
}
|
||||
tool.setClassLoader(classLoader);
|
||||
tool.setBytecodeLogging(bytecodeLogging);
|
||||
tool.setMainClass(mainClass);
|
||||
tool.setMainPageIncluded(mainPageIncluded);
|
||||
tool.setMinifying(minifying);
|
||||
tool.setNumThreads(numThreads);
|
||||
tool.setRuntime(runtime);
|
||||
tool.setTargetDirectory(targetDirectory);
|
||||
tool.setTargetFileName(targetFileName);
|
||||
tool.getTransformers().addAll(instantiateTransformers(classLoader));
|
||||
if (classAliases != null) {
|
||||
for (ClassAlias alias : classAliases) {
|
||||
vm.exportType(alias.getAlias(), alias.getClassName());
|
||||
}
|
||||
tool.getClassAliases().addAll(Arrays.asList(classAliases));
|
||||
}
|
||||
if (methodAliases != null) {
|
||||
for (MethodAlias methodAlias : methodAliases) {
|
||||
MethodReference ref = new MethodReference(methodAlias.getClassName(), methodAlias.getMethodName(),
|
||||
MethodDescriptor.parseSignature(methodAlias.getDescriptor()));
|
||||
TeaVMEntryPoint entryPoint = vm.entryPoint(methodAlias.getAlias(), ref);
|
||||
if (methodAlias.getTypes() != null) {
|
||||
for (int i = 0; i < methodAlias.getTypes().length; ++i) {
|
||||
String types = methodAlias.getTypes()[i];
|
||||
if (types != null) {
|
||||
for (String type : types.split(" +")) {
|
||||
type = type.trim();
|
||||
if (!type.isEmpty()) {
|
||||
entryPoint.withValue(i, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
targetDirectory.mkdirs();
|
||||
try (FileWriter writer = new FileWriter(new File(targetDirectory, targetFileName))) {
|
||||
if (runtime == RuntimeCopyOperation.MERGED) {
|
||||
vm.add(runtimeInjector);
|
||||
}
|
||||
vm.build(writer, new DirectoryBuildTarget(targetDirectory));
|
||||
vm.checkForMissingItems();
|
||||
log.info("JavaScript file successfully built");
|
||||
}
|
||||
if (runtime == RuntimeCopyOperation.SEPARATE) {
|
||||
resourceToFile("org/teavm/javascript/runtime.js", "runtime.js");
|
||||
}
|
||||
if (mainPageIncluded) {
|
||||
String text;
|
||||
try (Reader reader = new InputStreamReader(classLoader.getResourceAsStream(
|
||||
"org/teavm/maven/main.html"), "UTF-8")) {
|
||||
text = IOUtils.toString(reader).replace("${classes.js}", targetFileName);
|
||||
}
|
||||
File mainPageFile = new File(targetDirectory, "main.html");
|
||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(mainPageFile), "UTF-8")) {
|
||||
writer.append(text);
|
||||
tool.getMethodAliases().addAll(Arrays.asList(methodAliases));
|
||||
}
|
||||
if (properties != null) {
|
||||
tool.getProperties().putAll(properties);
|
||||
}
|
||||
tool.generate();
|
||||
} catch (RuntimeException e) {
|
||||
throw new MojoExecutionException("Unexpected error occured", e);
|
||||
} catch (IOException e) {
|
||||
} catch (TeaVMToolException e) {
|
||||
throw new MojoExecutionException("IO error occured", e);
|
||||
} finally {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractRendererListener runtimeInjector = new AbstractRendererListener() {
|
||||
@Override
|
||||
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException {
|
||||
@SuppressWarnings("resource")
|
||||
StringWriter writer = new StringWriter();
|
||||
resourceToWriter("org/teavm/javascript/runtime.js", writer);
|
||||
writer.close();
|
||||
context.getWriter().append(writer.toString()).newLine();
|
||||
}
|
||||
};
|
||||
|
||||
private List<ClassHolderTransformer> instantiateTransformers(ClassLoader classLoader)
|
||||
throws MojoExecutionException {
|
||||
|
@ -316,18 +240,4 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
throw new MojoExecutionException("Error gathering classpath information", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void resourceToFile(String resource, String fileName) throws IOException {
|
||||
try (InputStream input = BuildJavascriptMojo.class.getClassLoader().getResourceAsStream(resource)) {
|
||||
try (OutputStream output = new FileOutputStream(new File(targetDirectory, fileName))) {
|
||||
IOUtils.copy(input, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resourceToWriter(String resource, Writer writer) throws IOException {
|
||||
try (InputStream input = BuildJavascriptMojo.class.getClassLoader().getResourceAsStream(resource)) {
|
||||
IOUtils.copy(input, writer, "UTF-8");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
*/
|
||||
package org.teavm.maven;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.MalformedURLException;
|
||||
|
@ -25,7 +26,6 @@ import java.util.*;
|
|||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
|
@ -36,16 +36,11 @@ import org.apache.maven.plugins.annotations.Mojo;
|
|||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.teavm.common.FiniteExecutor;
|
||||
import org.teavm.common.SimpleFiniteExecutor;
|
||||
import org.teavm.common.ThreadPoolFiniteExecutor;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.parsing.ClasspathClassHolderSource;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.testing.JUnitTestAdapter;
|
||||
import org.teavm.testing.TestAdapter;
|
||||
import org.teavm.vm.DirectoryBuildTarget;
|
||||
import org.teavm.vm.TeaVM;
|
||||
import org.teavm.vm.TeaVMBuilder;
|
||||
import org.teavm.tooling.TeaVMTestTool;
|
||||
import org.teavm.tooling.TeaVMToolException;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -57,11 +52,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
private static Set<String> testScopes = new HashSet<>(Arrays.asList(
|
||||
Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME,
|
||||
Artifact.SCOPE_PROVIDED));
|
||||
private Map<String, List<MethodReference>> groupedMethods = new HashMap<>();
|
||||
private Map<MethodReference, String> fileNames = new HashMap<>();
|
||||
private List<MethodReference> testMethods = new ArrayList<>();
|
||||
private List<String> testClasses = new ArrayList<>();
|
||||
private TestAdapter adapter;
|
||||
|
||||
@Component
|
||||
private MavenProject project;
|
||||
|
@ -93,16 +83,14 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
@Parameter
|
||||
private String[] transformers;
|
||||
|
||||
private List<ClassHolderTransformer> transformerInstances;
|
||||
|
||||
@Parameter
|
||||
private String[] additionalScripts;
|
||||
|
||||
private List<String> additionalScriptLocalPaths = new ArrayList<>();
|
||||
|
||||
@Parameter
|
||||
private Properties properties;
|
||||
|
||||
private TeaVMTestTool tool = new TeaVMTestTool();
|
||||
|
||||
public void setProject(MavenProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
@ -154,124 +142,33 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
getLog().info("Tests build skipped as specified by system property");
|
||||
return;
|
||||
}
|
||||
Runnable finalizer = null;
|
||||
try {
|
||||
final ClassLoader classLoader = prepareClassLoader();
|
||||
createAdapter(classLoader);
|
||||
getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'");
|
||||
tool.setClassLoader(classLoader);
|
||||
tool.setAdapter(createAdapter(classLoader));
|
||||
findTestClasses(classLoader, testFiles, "");
|
||||
if (scanDependencies) {
|
||||
findTestsInDependencies(classLoader);
|
||||
}
|
||||
final Log log = getLog();
|
||||
new File(outputDir, "tests").mkdirs();
|
||||
new File(outputDir, "res").mkdirs();
|
||||
resourceToFile("org/teavm/javascript/runtime.js", "res/runtime.js");
|
||||
resourceToFile("org/teavm/maven/res/junit-support.js", "res/junit-support.js");
|
||||
resourceToFile("org/teavm/maven/res/junit.css", "res/junit.css");
|
||||
resourceToFile("org/teavm/maven/res/class_obj.png", "res/class_obj.png");
|
||||
resourceToFile("org/teavm/maven/res/control-000-small.png", "res/control-000-small.png");
|
||||
resourceToFile("org/teavm/maven/res/methpub_obj.png", "res/methpub_obj.png");
|
||||
resourceToFile("org/teavm/maven/res/package_obj.png", "res/package_obj.png");
|
||||
resourceToFile("org/teavm/maven/res/tick-small-red.png", "res/tick-small-red.png");
|
||||
resourceToFile("org/teavm/maven/res/tick-small.png", "res/tick-small.png");
|
||||
resourceToFile("org/teavm/maven/res/toggle-small-expand.png", "res/toggle-small-expand.png");
|
||||
resourceToFile("org/teavm/maven/res/toggle-small.png", "res/toggle-small.png");
|
||||
resourceToFile("org/teavm/maven/junit.html", "junit.html");
|
||||
final ClassHolderSource classSource = new ClasspathClassHolderSource(classLoader);
|
||||
for (String testClass : testClasses) {
|
||||
ClassHolder classHolder = classSource.get(testClass);
|
||||
if (classHolder == null) {
|
||||
throw new MojoFailureException("Could not find class " + testClass);
|
||||
tool.getTransformers().addAll(instantiateTransformers(classLoader));
|
||||
tool.setLog(new MavenTeaVMToolLog(getLog()));
|
||||
tool.setOutputDir(outputDir);
|
||||
tool.setNumThreads(numThreads);
|
||||
tool.setMinifying(minifying);
|
||||
if (properties != null) {
|
||||
tool.getProperties().putAll(properties);
|
||||
}
|
||||
findTests(classHolder);
|
||||
}
|
||||
|
||||
transformerInstances = instantiateTransformers(classLoader);
|
||||
includeAdditionalScripts(classLoader);
|
||||
File allTestsFile = new File(outputDir, "tests/all.js");
|
||||
try (Writer allTestsWriter = new OutputStreamWriter(new FileOutputStream(allTestsFile), "UTF-8")) {
|
||||
allTestsWriter.write("prepare = function() {\n");
|
||||
allTestsWriter.write(" return new JUnitServer(document.body).readTests([");
|
||||
boolean first = true;
|
||||
for (String testClass : testClasses) {
|
||||
if (!first) {
|
||||
allTestsWriter.append(",");
|
||||
}
|
||||
first = false;
|
||||
allTestsWriter.append("\n { name : \"").append(testClass).append("\", methods : [");
|
||||
boolean firstMethod = true;
|
||||
for (MethodReference methodRef : groupedMethods.get(testClass)) {
|
||||
String scriptName = "tests/" + fileNames.size() + ".js";
|
||||
fileNames.put(methodRef, scriptName);
|
||||
if (!firstMethod) {
|
||||
allTestsWriter.append(",");
|
||||
}
|
||||
firstMethod = false;
|
||||
allTestsWriter.append("\n { name : \"" + methodRef.getName() + "\", script : \"" +
|
||||
scriptName + "\", expected : [");
|
||||
MethodHolder methodHolder = classSource.get(testClass).getMethod(
|
||||
methodRef.getDescriptor());
|
||||
boolean firstException = true;
|
||||
for (String exception : adapter.getExpectedExceptions(methodHolder)) {
|
||||
if (!firstException) {
|
||||
allTestsWriter.append(", ");
|
||||
}
|
||||
firstException = false;
|
||||
allTestsWriter.append("\"" + exception + "\"");
|
||||
}
|
||||
allTestsWriter.append("], additionalScripts : [");
|
||||
for (int i = 0; i < additionalScriptLocalPaths.size(); ++i) {
|
||||
if (i > 0) {
|
||||
allTestsWriter.append(", ");
|
||||
}
|
||||
escapeString(additionalScriptLocalPaths.get(i), allTestsWriter);
|
||||
}
|
||||
allTestsWriter.append("] }");
|
||||
}
|
||||
allTestsWriter.append("] }");
|
||||
}
|
||||
allTestsWriter.write("], function() {}); }");
|
||||
}
|
||||
int methodsGenerated = 0;
|
||||
log.info("Generating test files");
|
||||
FiniteExecutor executor = new SimpleFiniteExecutor();
|
||||
if (numThreads != 1) {
|
||||
int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors();
|
||||
final ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads);
|
||||
finalizer = new Runnable() {
|
||||
@Override public void run() {
|
||||
threadedExecutor.stop();
|
||||
}
|
||||
};
|
||||
executor = threadedExecutor;
|
||||
}
|
||||
for (final MethodReference method : testMethods) {
|
||||
executor.execute(new Runnable() {
|
||||
@Override public void run() {
|
||||
log.debug("Building test for " + method);
|
||||
try {
|
||||
decompileClassesForTest(classLoader, new CopyClassHolderSource(classSource), method,
|
||||
fileNames.get(method), new SimpleFiniteExecutor());
|
||||
} catch (IOException e) {
|
||||
log.error("Error generating JavaScript", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
++methodsGenerated;
|
||||
}
|
||||
executor.complete();
|
||||
log.info("Test files successfully generated for " + methodsGenerated + " method(s).");
|
||||
} catch (IOException e) {
|
||||
throw new MojoFailureException("IO error occured generating JavaScript files", e);
|
||||
} finally {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
if (additionalScripts != null) {
|
||||
tool.getAdditionalScripts().addAll(Arrays.asList(additionalScripts));
|
||||
}
|
||||
tool.generate();
|
||||
} catch (TeaVMToolException e) {
|
||||
throw new MojoFailureException("Error occured generating JavaScript files", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createAdapter(ClassLoader classLoader) throws MojoExecutionException {
|
||||
private TestAdapter createAdapter(ClassLoader classLoader) throws MojoExecutionException {
|
||||
Class<?> adapterClsRaw;
|
||||
try {
|
||||
adapterClsRaw = Class.forName(adapterClass, true, classLoader);
|
||||
|
@ -290,7 +187,7 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
throw new MojoExecutionException("No default constructor found for test adapter " + adapterClass, e);
|
||||
}
|
||||
try {
|
||||
adapter = cons.newInstance();
|
||||
return cons.newInstance();
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
throw new MojoExecutionException("Error creating test adapter", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
|
@ -330,89 +227,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
}
|
||||
}
|
||||
|
||||
private void decompileClassesForTest(ClassLoader classLoader, ClassHolderSource classSource,
|
||||
MethodReference methodRef, String targetName, FiniteExecutor executor) throws IOException {
|
||||
TeaVM vm = new TeaVMBuilder()
|
||||
.setClassLoader(classLoader)
|
||||
.setClassSource(classSource)
|
||||
.setExecutor(executor)
|
||||
.build();
|
||||
vm.setProperties(properties);
|
||||
vm.setMinifying(minifying);
|
||||
vm.installPlugins();
|
||||
new TestExceptionPlugin().install(vm);
|
||||
for (ClassHolderTransformer transformer : transformerInstances) {
|
||||
vm.add(transformer);
|
||||
}
|
||||
File file = new File(outputDir, targetName);
|
||||
try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
|
||||
MethodReference cons = new MethodReference(methodRef.getClassName(),
|
||||
new MethodDescriptor("<init>", ValueType.VOID));
|
||||
MethodReference exceptionMsg = new MethodReference("java.lang.Throwable", "getMessage",
|
||||
ValueType.object("java.lang.String"));
|
||||
vm.entryPoint("initInstance", cons);
|
||||
vm.entryPoint("runTest", methodRef).withValue(0, cons.getClassName());
|
||||
vm.entryPoint("extractException", exceptionMsg);
|
||||
vm.exportType("TestClass", cons.getClassName());
|
||||
vm.build(innerWriter, new DirectoryBuildTarget(outputDir));
|
||||
if (!vm.hasMissingItems()) {
|
||||
innerWriter.append("\n");
|
||||
innerWriter.append("\nJUnitClient.run();");
|
||||
innerWriter.close();
|
||||
} else {
|
||||
innerWriter.append("JUnitClient.reportError(\n");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
vm.showMissingItems(sb);
|
||||
escapeStringLiteral(sb.toString(), innerWriter);
|
||||
innerWriter.append(");");
|
||||
getLog().warn("Error building test " + methodRef);
|
||||
getLog().warn(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void escapeStringLiteral(String text, Writer writer) throws IOException {
|
||||
int index = 0;
|
||||
while (true) {
|
||||
int next = text.indexOf('\n', index);
|
||||
if (next < 0) {
|
||||
break;
|
||||
}
|
||||
escapeString(text.substring(index, next + 1), writer);
|
||||
writer.append(" +\n");
|
||||
index = next + 1;
|
||||
}
|
||||
escapeString(text.substring(index), writer);
|
||||
}
|
||||
|
||||
private void escapeString(String string, Writer writer) throws IOException {
|
||||
writer.append('\"');
|
||||
for (int i = 0; i < string.length(); ++i) {
|
||||
char c = string.charAt(i);
|
||||
switch (c) {
|
||||
case '"':
|
||||
writer.append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
writer.append("\\\\");
|
||||
break;
|
||||
case '\n':
|
||||
writer.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
writer.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
writer.append("\\t");
|
||||
break;
|
||||
default:
|
||||
writer.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
writer.append('\"');
|
||||
}
|
||||
|
||||
private void findTestsInDependencies(ClassLoader classLoader) throws MojoExecutionException {
|
||||
try {
|
||||
Log log = getLog();
|
||||
|
@ -477,8 +291,8 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
}
|
||||
try {
|
||||
Class<?> candidate = Class.forName(className, true, classLoader);
|
||||
if (adapter.acceptClass(candidate)) {
|
||||
testClasses.add(candidate.getName());
|
||||
if (tool.getAdapter().acceptClass(candidate)) {
|
||||
tool.getTestClasses().add(candidate.getName());
|
||||
getLog().info("Test class detected: " + candidate.getName());
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
|
@ -486,28 +300,6 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
}
|
||||
}
|
||||
|
||||
private void findTests(ClassHolder cls) {
|
||||
for (MethodHolder method : cls.getMethods()) {
|
||||
if (adapter.acceptMethod(method)) {
|
||||
MethodReference ref = new MethodReference(cls.getName(), method.getDescriptor());
|
||||
testMethods.add(ref);
|
||||
List<MethodReference> group = groupedMethods.get(cls.getName());
|
||||
if (group == null) {
|
||||
group = new ArrayList<>();
|
||||
groupedMethods.put(cls.getName(), group);
|
||||
}
|
||||
group.add(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resourceToFile(String resource, String fileName) throws IOException {
|
||||
try (InputStream input = BuildJavascriptTestMojo.class.getClassLoader().getResourceAsStream(resource)) {
|
||||
try (OutputStream output = new FileOutputStream(new File(outputDir, fileName))) {
|
||||
IOUtils.copy(input, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<ClassHolderTransformer> instantiateTransformers(ClassLoader classLoader)
|
||||
throws MojoExecutionException {
|
||||
|
@ -543,29 +335,4 @@ public class BuildJavascriptTestMojo extends AbstractMojo {
|
|||
}
|
||||
return transformerInstances;
|
||||
}
|
||||
|
||||
private void includeAdditionalScripts(ClassLoader classLoader) throws MojoExecutionException {
|
||||
if (additionalScripts == null) {
|
||||
return;
|
||||
}
|
||||
for (String script : additionalScripts) {
|
||||
String simpleName = script.substring(script.lastIndexOf('/') + 1);
|
||||
additionalScriptLocalPaths.add("tests/" + simpleName);
|
||||
if (classLoader.getResource(script) == null) {
|
||||
throw new MojoExecutionException("Additional script " + script + " was not found");
|
||||
}
|
||||
File file = new File(outputDir, "tests/" + simpleName);
|
||||
try (InputStream in = classLoader.getResourceAsStream(script)) {
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
try(OutputStream out = new FileOutputStream(file)) {
|
||||
IOUtils.copy(in, out);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new MojoExecutionException("Error copying additional script " + script, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package org.teavm.maven;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.teavm.tooling.TeaVMToolLog;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class MavenTeaVMToolLog implements TeaVMToolLog {
|
||||
private Log log;
|
||||
|
||||
public MavenTeaVMToolLog(Log log) {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String text) {
|
||||
log.info(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text) {
|
||||
log.debug(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text) {
|
||||
log.warn(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text) {
|
||||
log.error(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String text, Throwable e) {
|
||||
log.info(text, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text, Throwable e) {
|
||||
log.debug(text, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text, Throwable e) {
|
||||
log.warn(text, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text, Throwable e) {
|
||||
log.error(text, e);
|
||||
}
|
||||
}
|