mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add IDEA run configuration that runs dev server
This commit is contained in:
parent
bab0cd59a6
commit
d7d4dc1571
|
@ -1,9 +1,11 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="IDEA" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType" factoryName="Plugin">
|
||||
<configuration default="false" name="IDEA" type="#org.jetbrains.idea.devkit.run.PluginConfigurationType">
|
||||
<module name="teavm-idea" />
|
||||
<option name="VM_PARAMETERS" value="-Xmx1024m -Xms256m -ea" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<predefined_log_file id="idea.log" enabled="true" />
|
||||
<method />
|
||||
<predefined_log_file enabled="true" id="idea.log" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
|
@ -80,6 +80,11 @@
|
|||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
|
@ -135,6 +140,15 @@
|
|||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>html/**</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
|
@ -151,7 +165,7 @@
|
|||
</includes>
|
||||
</artifactSet>
|
||||
<relocations>
|
||||
<relocation>cd
|
||||
<relocation>
|
||||
<pattern>org.objectweb.asm</pattern>
|
||||
<shadedPattern>org.teavm.asm</shadedPattern>
|
||||
</relocation>
|
||||
|
|
11
core/pom.xml
11
core/pom.xml
|
@ -107,10 +107,19 @@
|
|||
<artifactSet>
|
||||
<excludes>
|
||||
<exclude>junit:junit</exclude>
|
||||
<exclude>org:teavm:*</exclude>
|
||||
<exclude>org.teavm:teavm-interop</exclude>
|
||||
<exclude>org.teavm:teavm-metaprogramming-api</exclude>
|
||||
<exclude>com.fasterxml.jackson.core:jackson-annotations</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>**/module-info.class</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.objectweb.asm</pattern>
|
||||
|
|
|
@ -79,6 +79,13 @@ public class InMemoryMethodNodeCache implements MethodNodeCache {
|
|||
newAsyncItems.clear();
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
cache.clear();
|
||||
newItems.clear();
|
||||
asyncCache.clear();
|
||||
newAsyncItems.clear();
|
||||
}
|
||||
|
||||
static final class RegularItem {
|
||||
final RegularMethodNode node;
|
||||
final String[] dependencies;
|
||||
|
|
|
@ -59,6 +59,11 @@ public class InMemoryProgramCache implements ProgramCache {
|
|||
newItems.clear();
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
cache.clear();
|
||||
newItems.clear();
|
||||
}
|
||||
|
||||
static final class Item {
|
||||
final Program program;
|
||||
final String[] dependencies;
|
||||
|
|
|
@ -62,4 +62,9 @@ public class MemoryCachedClassReaderSource implements ClassReaderSource, CacheSt
|
|||
cache.keySet().removeAll(classes);
|
||||
freshClasses.removeAll(classes);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
cache.clear();
|
||||
freshClasses.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -365,7 +365,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
dependencyAnalyzer.setAsyncSupported(target.isAsyncSupported());
|
||||
dependencyAnalyzer.setInterruptor(() -> {
|
||||
int progress = lastKnownClasses > 0 ? dependencyAnalyzer.getReachableClasses().size() : 0;
|
||||
return progressListener.progressReached(progress) == TeaVMProgressFeedback.CONTINUE;
|
||||
cancelled |= progressListener.progressReached(progress) != TeaVMProgressFeedback.CONTINUE;
|
||||
return !cancelled;
|
||||
});
|
||||
target.contributeDependencies(dependencyAnalyzer);
|
||||
dependencyAnalyzer.processDependencies();
|
||||
|
|
|
@ -34,17 +34,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
|
|
|
@ -43,17 +43,6 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
|
|
|
@ -38,17 +38,6 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
|
|
|
@ -57,17 +57,6 @@
|
|||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -46,6 +46,7 @@
|
|||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
|
@ -82,17 +83,6 @@
|
|||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
|
|
10
pom.xml
10
pom.xml
|
@ -197,11 +197,6 @@
|
|||
<artifactId>rhino</artifactId>
|
||||
<version>${rhino.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
@ -286,6 +281,11 @@
|
|||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
|
|
@ -86,7 +86,7 @@ public final class BenchmarkStarter {
|
|||
private static void render() {
|
||||
CanvasRenderingContext2D context = (CanvasRenderingContext2D) canvas.getContext("2d");
|
||||
context.setFillStyle("white");
|
||||
context.setStrokeStyle("grey");
|
||||
context.setStrokeStyle("red");
|
||||
context.fillRect(0, 0, 600, 600);
|
||||
context.save();
|
||||
context.translate(0, 600);
|
||||
|
|
|
@ -48,13 +48,6 @@
|
|||
<artifactId>teavm-jso-apis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-jso-apis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-metaprogramming-impl</artifactId>
|
||||
|
|
|
@ -110,18 +110,6 @@
|
|||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>org.teavm.cli.TeaVMRunner</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
|
@ -134,7 +122,16 @@
|
|||
<configuration>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>org.teavm.cli.TeaVMRunner</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons</pattern>
|
||||
<shadedPattern>org.teavm.apachecommons</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -114,7 +114,7 @@ public final class TeaVMDevServerRunner {
|
|||
|
||||
devServer.setIndicator(commandLine.hasOption("indicator"));
|
||||
devServer.setReloadedAutomatically(commandLine.hasOption("auto-reload"));
|
||||
devServer.setVerbose(commandLine.hasOption('v'));
|
||||
devServer.setLog(new ConsoleTeaVMToolLog(commandLine.hasOption('v')));
|
||||
if (commandLine.hasOption("port")) {
|
||||
try {
|
||||
devServer.setPort(Integer.parseInt(commandLine.getOptionValue("port")));
|
||||
|
|
|
@ -15,11 +15,18 @@
|
|||
*/
|
||||
package org.teavm.tooling;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ProgramReader;
|
||||
import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.instructions.AbstractInstructionReader;
|
||||
import org.teavm.vm.TeaVM;
|
||||
|
||||
class InstructionLocationReader extends AbstractInstructionReader {
|
||||
public class InstructionLocationReader extends AbstractInstructionReader {
|
||||
private Set<String> resources;
|
||||
|
||||
public InstructionLocationReader(Set<String> resources) {
|
||||
|
@ -32,4 +39,32 @@ class InstructionLocationReader extends AbstractInstructionReader {
|
|||
resources.add(location.getFileName());
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> extractUsedResources(TeaVM vm) {
|
||||
Set<String> resources = new LinkedHashSet<>();
|
||||
ClassReaderSource classSource = vm.getDependencyClassSource();
|
||||
InstructionLocationReader reader = new InstructionLocationReader(resources);
|
||||
for (MethodReference methodRef : vm.getMethods()) {
|
||||
ClassReader cls = classSource.get(methodRef.getClassName());
|
||||
if (cls == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ProgramReader program = method.getProgram();
|
||||
if (program == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
program.basicBlockAt(i).readAllInstructions(reader);
|
||||
}
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,11 +52,7 @@ import org.teavm.diagnostics.ProblemProvider;
|
|||
import org.teavm.model.ClassHolderSource;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.PreOptimizingClassHolderSource;
|
||||
import org.teavm.model.ProgramReader;
|
||||
import org.teavm.parsing.ClasspathClassHolderSource;
|
||||
import org.teavm.tooling.sources.SourceFileProvider;
|
||||
import org.teavm.tooling.sources.SourceFilesCopier;
|
||||
|
@ -268,31 +264,7 @@ public class TeaVMTool {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Set<String> resources = new HashSet<>();
|
||||
ClassReaderSource classSource = vm.getDependencyClassSource();
|
||||
InstructionLocationReader reader = new InstructionLocationReader(resources);
|
||||
for (MethodReference methodRef : vm.getMethods()) {
|
||||
ClassReader cls = classSource.get(methodRef.getClassName());
|
||||
if (cls == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ProgramReader program = method.getProgram();
|
||||
if (program == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
program.basicBlockAt(i).readAllInstructions(reader);
|
||||
}
|
||||
}
|
||||
|
||||
return resources;
|
||||
return InstructionLocationReader.extractUsedResources(vm);
|
||||
}
|
||||
|
||||
public void addSourceFileProvider(SourceFileProvider sourceFileProvider) {
|
||||
|
|
|
@ -66,24 +66,6 @@
|
|||
<artifactId>teavm-tooling</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-classlib</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-metaprogramming-impl</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-jso-impl</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
|
|
@ -96,8 +96,12 @@ public class CodeServlet extends HttpServlet {
|
|||
|
||||
private final Set<CodeWsEndpoint> wsEndpoints = new LinkedHashSet<>();
|
||||
private final Object statusLock = new Object();
|
||||
private volatile boolean cancelRequested;
|
||||
private boolean compiling;
|
||||
private double progress;
|
||||
private boolean waiting;
|
||||
private Thread buildThread;
|
||||
private List<DevServerListener> listeners = new ArrayList<>();
|
||||
|
||||
public CodeServlet(String mainClass, String[] classPath) {
|
||||
this.mainClass = mainClass;
|
||||
|
@ -160,6 +164,37 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
}
|
||||
|
||||
public void addListener(DevServerListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
synchronized (statusLock) {
|
||||
if (compiling) {
|
||||
return;
|
||||
}
|
||||
astCache.invalidate();
|
||||
programCache.invalidate();
|
||||
classSource.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void buildProject() {
|
||||
synchronized (statusLock) {
|
||||
if (waiting) {
|
||||
buildThread.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelBuild() {
|
||||
synchronized (statusLock) {
|
||||
if (compiling) {
|
||||
cancelRequested = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
String path = req.getPathInfo();
|
||||
|
@ -206,15 +241,20 @@ public class CodeServlet extends HttpServlet {
|
|||
public void destroy() {
|
||||
super.destroy();
|
||||
stopped = true;
|
||||
synchronized (statusLock) {
|
||||
if (waiting) {
|
||||
buildThread.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws ServletException {
|
||||
super.init();
|
||||
Thread thread = new Thread(this::runTeaVM);
|
||||
thread.setDaemon(true);
|
||||
thread.setName("TeaVM compiler");
|
||||
thread.start();
|
||||
buildThread = thread;
|
||||
}
|
||||
|
||||
private boolean serveSourceFile(String fileName, HttpServletResponse resp) throws IOException {
|
||||
|
@ -306,12 +346,20 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
try {
|
||||
synchronized (statusLock) {
|
||||
waiting = true;
|
||||
}
|
||||
watcher.waitForChange(750);
|
||||
synchronized (statusLock) {
|
||||
waiting = false;
|
||||
}
|
||||
log.info("Changes detected. Recompiling.");
|
||||
} catch (InterruptedException e) {
|
||||
log.info("Build thread interrupted");
|
||||
break;
|
||||
if (stopped) {
|
||||
break;
|
||||
}
|
||||
log.info("Build triggered by user");
|
||||
}
|
||||
log.info("Changes detected. Recompiling.");
|
||||
|
||||
List<String> staleClasses = getChangedClasses(watcher.grabChangedFiles());
|
||||
if (staleClasses.size() > 15) {
|
||||
|
@ -325,6 +373,7 @@ public class CodeServlet extends HttpServlet {
|
|||
|
||||
classSource.evict(staleClasses);
|
||||
}
|
||||
log.info("Build process stopped");
|
||||
} catch (Throwable e) {
|
||||
log.error("Compile server crashed", e);
|
||||
} finally {
|
||||
|
@ -359,6 +408,9 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
private void buildOnce() {
|
||||
fireBuildStarted();
|
||||
reportProgress(0);
|
||||
|
||||
DebugInformationBuilder debugInformationBuilder = new DebugInformationBuilder();
|
||||
ClassLoader classLoader = initClassLoader();
|
||||
classSource.setUnderlyingSource(new PreOptimizingClassHolderSource(
|
||||
|
@ -390,7 +442,6 @@ public class CodeServlet extends HttpServlet {
|
|||
log.info("Starting build");
|
||||
progressListener.last = 0;
|
||||
progressListener.lastTime = System.currentTimeMillis();
|
||||
reportProgress(0);
|
||||
vm.build(buildTarget, fileName);
|
||||
addIndicator();
|
||||
generateDebug(debugInformationBuilder);
|
||||
|
@ -450,6 +501,7 @@ public class CodeServlet extends HttpServlet {
|
|||
private void postBuild(TeaVM vm, long startTime) {
|
||||
if (!vm.wasCancelled()) {
|
||||
log.info("Recompiled stale methods: " + programCache.getPendingItemsCount());
|
||||
fireBuildComplete(vm);
|
||||
if (vm.getProblemProvider().getSevereProblems().isEmpty()) {
|
||||
log.info("Build complete successfully");
|
||||
saveNewResult();
|
||||
|
@ -466,11 +518,13 @@ public class CodeServlet extends HttpServlet {
|
|||
TeaVMProblemRenderer.describeProblems(vm, log);
|
||||
} else {
|
||||
log.info("Build cancelled");
|
||||
fireBuildCancelled();
|
||||
}
|
||||
|
||||
astCache.discard();
|
||||
programCache.discard();
|
||||
buildTarget.clear();
|
||||
cancelRequested = false;
|
||||
}
|
||||
|
||||
private void printStats(TeaVM vm, long startTime) {
|
||||
|
@ -553,6 +607,10 @@ public class CodeServlet extends HttpServlet {
|
|||
for (CodeWsEndpoint endpoint : endpoints) {
|
||||
endpoint.progress(progress);
|
||||
}
|
||||
|
||||
for (DevServerListener listener : listeners) {
|
||||
listener.compilationProgress(progress);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportCompilationComplete(boolean success) {
|
||||
|
@ -573,6 +631,25 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
}
|
||||
|
||||
private void fireBuildStarted() {
|
||||
for (DevServerListener listener : listeners) {
|
||||
listener.compilationStarted();
|
||||
}
|
||||
}
|
||||
|
||||
private void fireBuildCancelled() {
|
||||
for (DevServerListener listener : listeners) {
|
||||
listener.compilationCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
private void fireBuildComplete(TeaVM vm) {
|
||||
CodeServletBuildResult result = new CodeServletBuildResult(vm, new ArrayList<>(buildTarget.getNames()));
|
||||
for (DevServerListener listener : listeners) {
|
||||
listener.compilationComplete(result);
|
||||
}
|
||||
}
|
||||
|
||||
private final ProgressListenerImpl progressListener = new ProgressListenerImpl();
|
||||
|
||||
class ProgressListenerImpl implements TeaVMProgressListener {
|
||||
|
@ -622,6 +699,11 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
private TeaVMProgressFeedback getResult() {
|
||||
if (cancelRequested) {
|
||||
log.info("Trying to cancel compilation due to user request");
|
||||
return TeaVMProgressFeedback.CANCEL;
|
||||
}
|
||||
|
||||
if (stopped) {
|
||||
log.info("Trying to cancel compilation due to server stopping");
|
||||
return TeaVMProgressFeedback.CANCEL;
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2018 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.devserver;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.diagnostics.ProblemProvider;
|
||||
import org.teavm.tooling.InstructionLocationReader;
|
||||
import org.teavm.tooling.builder.BuildResult;
|
||||
import org.teavm.vm.TeaVM;
|
||||
|
||||
class CodeServletBuildResult implements BuildResult {
|
||||
private TeaVM vm;
|
||||
private List<String> generatedFiles;
|
||||
private Collection<String> usedResources;
|
||||
|
||||
public CodeServletBuildResult(TeaVM vm, List<String> generatedFiles) {
|
||||
this.vm = vm;
|
||||
this.generatedFiles = generatedFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallGraph getCallGraph() {
|
||||
return vm.getDependencyInfo().getCallGraph();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProblemProvider getProblems() {
|
||||
return vm.getProblemProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getUsedResources() {
|
||||
if (usedResources == null) {
|
||||
usedResources = InstructionLocationReader.extractUsedResources(vm);
|
||||
}
|
||||
return usedResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getClasses() {
|
||||
return vm.getClasses();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getGeneratedFiles() {
|
||||
return generatedFiles;
|
||||
}
|
||||
}
|
|
@ -30,7 +30,6 @@ import org.eclipse.jetty.server.ServerConnector;
|
|||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
|
||||
import org.teavm.tooling.ConsoleTeaVMToolLog;
|
||||
import org.teavm.tooling.TeaVMToolLog;
|
||||
|
||||
public class DevServer {
|
||||
|
@ -41,8 +40,9 @@ public class DevServer {
|
|||
private List<String> sourcePath = new ArrayList<>();
|
||||
private boolean indicator;
|
||||
private boolean reloadedAutomatically;
|
||||
private boolean verbose;
|
||||
private TeaVMToolLog log;
|
||||
private CodeServlet servlet;
|
||||
private List<DevServerListener> listeners = new ArrayList<>();
|
||||
|
||||
private Server server;
|
||||
private int port = 9090;
|
||||
|
@ -85,16 +85,27 @@ public class DevServer {
|
|||
this.reloadedAutomatically = reloadedAutomatically;
|
||||
}
|
||||
|
||||
public void setVerbose(boolean verbose) {
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
public List<String> getSourcePath() {
|
||||
return sourcePath;
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
servlet.invalidateCache();
|
||||
}
|
||||
|
||||
public void buildProject() {
|
||||
servlet.buildProject();
|
||||
}
|
||||
|
||||
public void cancelBuild() {
|
||||
servlet.cancelBuild();
|
||||
}
|
||||
|
||||
public void addListener(DevServerListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
log = new ConsoleTeaVMToolLog(verbose);
|
||||
server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(port);
|
||||
|
@ -103,7 +114,7 @@ public class DevServer {
|
|||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/");
|
||||
server.setHandler(context);
|
||||
CodeServlet servlet = new CodeServlet(mainClass, classPath);
|
||||
servlet = new CodeServlet(mainClass, classPath);
|
||||
servlet.setFileName(fileName);
|
||||
servlet.setPathToFile(pathToFile);
|
||||
servlet.setLog(log);
|
||||
|
@ -111,6 +122,9 @@ public class DevServer {
|
|||
servlet.setIndicator(indicator);
|
||||
servlet.setAutomaticallyReloaded(reloadedAutomatically);
|
||||
servlet.setPort(port);
|
||||
for (DevServerListener listener : listeners) {
|
||||
servlet.addListener(listener);
|
||||
}
|
||||
context.addServlet(new ServletHolder(servlet), "/*");
|
||||
|
||||
try {
|
||||
|
@ -129,6 +143,8 @@ public class DevServer {
|
|||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
server = null;
|
||||
servlet = null;
|
||||
}
|
||||
|
||||
private class DevServerEndpointConfig implements ServerEndpointConfig {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2018 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.devserver;
|
||||
|
||||
import org.teavm.tooling.builder.BuildResult;
|
||||
|
||||
public interface DevServerListener {
|
||||
void compilationStarted();
|
||||
|
||||
void compilationProgress(double progress);
|
||||
|
||||
void compilationComplete(BuildResult result);
|
||||
|
||||
void compilationCancelled();
|
||||
}
|
|
@ -44,23 +44,21 @@
|
|||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-tooling</artifactId>
|
||||
<version>${teavm.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-devserver</artifactId>
|
||||
<version>${teavm.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-classlib</artifactId>
|
||||
<version>${teavm.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-chrome-rdp</artifactId>
|
||||
<version>${teavm.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -125,6 +123,36 @@
|
|||
</atrifactSet>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<outputFile>dependencies/teavm.jar</outputFile>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>com.google.gson</pattern>
|
||||
<shadedPattern>org.teavm.shade.gson</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.jcraft.jzlib</pattern>
|
||||
<shadedPattern>org.teavm.shade.jzlib</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.eclipse.jetty</pattern>
|
||||
<shadedPattern>org.teavm.shade.jetty</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.joda.time</pattern>
|
||||
<shadedPattern>org.teavm.shade.jodatime</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.objectweb.asm</pattern>
|
||||
<shadedPattern>org.teavm.shade.jetty.asm</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.slf4j</pattern>
|
||||
<shadedPattern>org.teavm.shade.slf4j</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons</pattern>
|
||||
<shadedPattern>org.teavm.apachecommons</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -24,13 +24,16 @@ import java.util.Arrays;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.teavm.idea.devserver.DevServerRunner;
|
||||
import org.teavm.tooling.daemon.BuildDaemon;
|
||||
|
||||
public final class DaemonUtil {
|
||||
private static final Set<String> PLUGIN_FILES = new HashSet<>(Arrays.asList("teavm-jps-common.jar",
|
||||
"teavm-plugin.jar", "teavm.jar"));
|
||||
private static final String DAEMON_CLASS = BuildDaemon.class.getName().replace('.', '/') + ".class";
|
||||
private static final String DEV_SERVER_CLASS = DevServerRunner.class.getName().replace('.', '/') + ".class";
|
||||
private static final int DAEMON_CLASS_DEPTH;
|
||||
private static final int DEV_SERVER_CLASS_DEPTH;
|
||||
|
||||
static {
|
||||
int depth = 0;
|
||||
|
@ -40,6 +43,14 @@ public final class DaemonUtil {
|
|||
}
|
||||
}
|
||||
DAEMON_CLASS_DEPTH = depth;
|
||||
|
||||
depth = 0;
|
||||
for (int i = 0; i < DEV_SERVER_CLASS.length(); ++i) {
|
||||
if (DEV_SERVER_CLASS.charAt(i) == '/') {
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
DEV_SERVER_CLASS_DEPTH = depth;
|
||||
}
|
||||
|
||||
private DaemonUtil() {
|
||||
|
@ -64,6 +75,11 @@ public final class DaemonUtil {
|
|||
file = file.getParentFile();
|
||||
}
|
||||
targetFiles.add(file.getAbsolutePath());
|
||||
} else if (file.getPath().endsWith(DEV_SERVER_CLASS)) {
|
||||
for (int i = 0; i <= DEV_SERVER_CLASS_DEPTH; ++i) {
|
||||
file = file.getParentFile();
|
||||
}
|
||||
targetFiles.add(file.getAbsolutePath());
|
||||
} else if (file.isDirectory()) {
|
||||
for (File childFile : file.listFiles()) {
|
||||
findInHierarchy(childFile, targetFiles, visited);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea;
|
||||
|
||||
public interface DevServerRunnerListener {
|
||||
void error(String text);
|
||||
|
||||
void info(String text);
|
||||
|
||||
void stopped(int code);
|
||||
}
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package org.teavm.idea.debug;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||
import com.intellij.execution.configurations.LocatableConfigurationBase;
|
||||
|
@ -45,8 +44,7 @@ public class TeaVMDebugConfiguration extends LocatableConfigurationBase
|
|||
|
||||
@Nullable
|
||||
@Override
|
||||
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws
|
||||
ExecutionException {
|
||||
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) {
|
||||
return new TeaVMRunState(environment, port);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.diagnostics.Problem;
|
||||
|
||||
public class DevServerBuildResult implements Serializable {
|
||||
public CallGraph callGraph;
|
||||
public final List<Problem> problems = new ArrayList<>();
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
public class DevServerConfiguration {
|
||||
public String javaHome;
|
||||
public int maxHeap;
|
||||
public String mainClass;
|
||||
public String[] classPath;
|
||||
public String[] sourcePath;
|
||||
public boolean indicator;
|
||||
public boolean autoReload;
|
||||
public int port;
|
||||
public String pathToFile;
|
||||
public String fileName;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
public class DevServerInfo {
|
||||
public final int port;
|
||||
public final DevServerManager server;
|
||||
public final Process process;
|
||||
|
||||
DevServerInfo(int port, DevServerManager server, Process process) {
|
||||
this.port = port;
|
||||
this.server = server;
|
||||
this.process = process;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
public interface DevServerManager extends Remote {
|
||||
String ID = "TeaVM-BuildServer";
|
||||
|
||||
void stop() throws RemoteException;
|
||||
|
||||
void invalidateCache() throws RemoteException;
|
||||
|
||||
void buildProject() throws RemoteException;
|
||||
|
||||
void cancelBuild() throws RemoteException;
|
||||
|
||||
void addListener(DevServerManagerListener listener) throws RemoteException;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
public interface DevServerManagerListener extends Remote {
|
||||
void compilationStarted() throws RemoteException;
|
||||
|
||||
void compilationProgress(double progress) throws RemoteException;
|
||||
|
||||
void compilationComplete(DevServerBuildResult result) throws RemoteException;
|
||||
|
||||
void compilationCancelled() throws RemoteException;
|
||||
}
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.rmi.AlreadyBoundException;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
import java.rmi.NotBoundException;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.devserver.DevServer;
|
||||
import org.teavm.devserver.DevServerListener;
|
||||
import org.teavm.idea.DevServerRunnerListener;
|
||||
import org.teavm.tooling.ConsoleTeaVMToolLog;
|
||||
import org.teavm.tooling.builder.BuildResult;
|
||||
|
||||
public class DevServerRunner extends UnicastRemoteObject implements DevServerManager {
|
||||
private static final int MIN_PORT = 10000;
|
||||
private static final int MAX_PORT = 1 << 16;
|
||||
private static final String PORT_MESSAGE_PREFIX = "Build server port: ";
|
||||
private static final String DEBUG_PORT_PROPERTY = "teavm.server.debug.port";
|
||||
private int port;
|
||||
private Registry registry;
|
||||
private DevServer server;
|
||||
private List<DevServerManagerListener> listeners = new ArrayList<>();
|
||||
|
||||
private DevServerRunner(DevServer server) throws RemoteException {
|
||||
super();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
port = random.nextInt(MAX_PORT - MIN_PORT) + MIN_PORT;
|
||||
try {
|
||||
registry = LocateRegistry.createRegistry(port);
|
||||
} catch (RemoteException e) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
registry.bind(ID, this);
|
||||
} catch (RemoteException | AlreadyBoundException e) {
|
||||
throw new IllegalStateException("Could not bind remote service", e);
|
||||
}
|
||||
|
||||
this.server = server;
|
||||
server.addListener(devServerListener);
|
||||
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Could not create RMI registry");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache() {
|
||||
server.invalidateCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildProject() {
|
||||
server.buildProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelBuild() {
|
||||
server.cancelBuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(DevServerManagerListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
DevServer server = new DevServer();
|
||||
server.setLog(new ConsoleTeaVMToolLog(true));
|
||||
server.setMainClass(args[0]);
|
||||
List<String> classPath = new ArrayList<>();
|
||||
for (int i = 1; i < args.length; ++i) {
|
||||
switch (args[i]) {
|
||||
case "-c":
|
||||
classPath.add(args[++i]);
|
||||
break;
|
||||
case "-s":
|
||||
server.getSourcePath().add(args[++i]);
|
||||
break;
|
||||
case "-i":
|
||||
server.setIndicator(true);
|
||||
break;
|
||||
case "-a":
|
||||
server.setReloadedAutomatically(true);
|
||||
break;
|
||||
case "-p":
|
||||
server.setPort(Integer.parseInt(args[++i]));
|
||||
break;
|
||||
case "-d":
|
||||
server.setPathToFile(args[++i]);
|
||||
break;
|
||||
case "-f":
|
||||
server.setFileName(args[++i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
server.setClassPath(classPath.toArray(new String[0]));
|
||||
|
||||
DevServerRunner daemon = new DevServerRunner(server);
|
||||
System.out.println(PORT_MESSAGE_PREFIX + daemon.port);
|
||||
server.start();
|
||||
|
||||
try {
|
||||
daemon.registry.unbind(ID);
|
||||
UnicastRemoteObject.unexportObject(daemon, true);
|
||||
} catch (NoSuchObjectException e) {
|
||||
throw new IllegalStateException("Could not shutdown RMI registry", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static DevServerInfo start(String[] classPathEntries, DevServerConfiguration options,
|
||||
DevServerRunnerListener listener) throws IOException {
|
||||
String javaCommand = options.javaHome + "/bin/java";
|
||||
String classPath = String.join(File.pathSeparator, classPathEntries);
|
||||
List<String> arguments = new ArrayList<>();
|
||||
|
||||
arguments.addAll(Arrays.asList(javaCommand, "-cp", classPath, "-Xmx" + options.maxHeap + "m"));
|
||||
|
||||
String debugPort = System.getProperty(DEBUG_PORT_PROPERTY);
|
||||
if (debugPort != null) {
|
||||
arguments.add("-agentlib:jdwp=transport=dt_socket,quiet=y,server=y,address=" + debugPort + ",suspend=y");
|
||||
}
|
||||
|
||||
arguments.add(DevServerRunner.class.getName());
|
||||
arguments.add(options.mainClass);
|
||||
|
||||
if (options.indicator) {
|
||||
arguments.add("-i");
|
||||
}
|
||||
if (options.autoReload) {
|
||||
arguments.add("-a");
|
||||
}
|
||||
arguments.add("-d");
|
||||
arguments.add(options.pathToFile);
|
||||
arguments.add("-f");
|
||||
arguments.add(options.fileName);
|
||||
arguments.add("-p");
|
||||
arguments.add(Integer.toString(options.port));
|
||||
|
||||
for (String entry : options.classPath) {
|
||||
arguments.add("-c");
|
||||
arguments.add(entry);
|
||||
}
|
||||
for (String entry : options.sourcePath) {
|
||||
arguments.add("-s");
|
||||
arguments.add(entry);
|
||||
}
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(arguments.toArray(new String[0]));
|
||||
Process process = builder.start();
|
||||
BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream(),
|
||||
StandardCharsets.UTF_8));
|
||||
BufferedReader stderrReader = new BufferedReader(new InputStreamReader(process.getErrorStream(),
|
||||
StandardCharsets.UTF_8));
|
||||
String line = stdoutReader.readLine();
|
||||
if (line == null || !line.startsWith(PORT_MESSAGE_PREFIX)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (true) {
|
||||
line = stderrReader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
sb.append(line).append('\n');
|
||||
}
|
||||
stderrReader.close();
|
||||
stdoutReader.close();
|
||||
process.destroy();
|
||||
throw new IllegalStateException("Could not start daemon. Stderr: " + sb);
|
||||
}
|
||||
int port = Integer.parseInt(line.substring(PORT_MESSAGE_PREFIX.length()));
|
||||
|
||||
daemonThread("TeaVM devserver stdout", new ProcessOutputWatcher(stdoutReader, listener::info)).start();
|
||||
daemonThread("TeaVM devserver stderr", new ProcessOutputWatcher(stderrReader, listener::error)).start();
|
||||
daemonThread("TeaVM devserver monitor", () -> {
|
||||
int exitCode;
|
||||
try {
|
||||
exitCode = process.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
listener.stopped(exitCode);
|
||||
}).start();
|
||||
|
||||
DevServerManager service;
|
||||
try {
|
||||
Registry registry = LocateRegistry.getRegistry(port);
|
||||
service = (DevServerManager) registry.lookup(ID);
|
||||
} catch (RemoteException | NotBoundException e) {
|
||||
throw new RuntimeException("Error connecting TeaVM process", e);
|
||||
}
|
||||
|
||||
return new DevServerInfo(port, service, process);
|
||||
}
|
||||
|
||||
private static Thread daemonThread(String name, Runnable runnable) {
|
||||
Thread thread = new Thread(runnable);
|
||||
thread.setName(name);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
}
|
||||
|
||||
static class ProcessOutputWatcher implements Runnable {
|
||||
private BufferedReader reader;
|
||||
private Consumer<String> consumer;
|
||||
|
||||
ProcessOutputWatcher(BufferedReader reader, Consumer<String> consumer) {
|
||||
this.reader = reader;
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
consumer.accept(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final DevServerListener devServerListener = new DevServerListener() {
|
||||
@Override
|
||||
public void compilationStarted() {
|
||||
for (DevServerManagerListener listener : listeners) {
|
||||
try {
|
||||
listener.compilationStarted();
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compilationProgress(double v) {
|
||||
for (DevServerManagerListener listener : listeners) {
|
||||
try {
|
||||
listener.compilationProgress(v);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compilationComplete(BuildResult buildResult) {
|
||||
DevServerBuildResult result = new DevServerBuildResult();
|
||||
result.callGraph = buildResult.getCallGraph();
|
||||
result.problems.addAll(buildResult.getProblems().getProblems());
|
||||
for (DevServerManagerListener listener : listeners) {
|
||||
try {
|
||||
listener.compilationComplete(result);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compilationCancelled() {
|
||||
for (DevServerManagerListener listener : listeners) {
|
||||
try {
|
||||
listener.compilationCancelled();
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||
import com.intellij.execution.configurations.ModuleBasedConfiguration;
|
||||
import com.intellij.execution.configurations.RunConfiguration;
|
||||
import com.intellij.execution.configurations.RunConfigurationModule;
|
||||
import com.intellij.execution.configurations.RunProfileState;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.facet.FacetManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.util.xmlb.XmlSerializer;
|
||||
import com.intellij.util.xmlb.annotations.Property;
|
||||
import com.intellij.util.xmlb.annotations.Tag;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.teavm.idea.TeaVMFacetType;
|
||||
import org.teavm.idea.devserver.ui.TeaVMDevServerSettingsEditor;
|
||||
|
||||
public class TeaVMDevServerConfiguration
|
||||
extends ModuleBasedConfiguration<RunConfigurationModule> {
|
||||
private String mainClass = "";
|
||||
private String jdkPath;
|
||||
private int port = 9090;
|
||||
private String pathToFile = "";
|
||||
private String fileName = "classes.js";
|
||||
private boolean indicator = true;
|
||||
private boolean automaticallyReloaded;
|
||||
private int maxHeap = 1024;
|
||||
|
||||
public TeaVMDevServerConfiguration(
|
||||
@NotNull RunConfigurationModule configurationModule,
|
||||
@NotNull ConfigurationFactory factory) {
|
||||
super("TeaVM dev server", configurationModule, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Module> getValidModules() {
|
||||
Module[] modules = ModuleManager.getInstance(getProject()).getModules();
|
||||
List<Module> validModules = new ArrayList<>();
|
||||
for (Module module : modules) {
|
||||
FacetManager facetManager = FacetManager.getInstance(module);
|
||||
if (facetManager.getFacetByType(TeaVMFacetType.TYPE_ID) != null) {
|
||||
validModules.add(module);
|
||||
}
|
||||
}
|
||||
return validModules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(@NotNull Element element) throws InvalidDataException {
|
||||
super.readExternal(element);
|
||||
|
||||
Element child = element.getChild("teavm");
|
||||
if (child != null) {
|
||||
XmlSerializer.deserializeInto(this, child);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(@NotNull Element element) throws WriteExternalException {
|
||||
super.writeExternal(element);
|
||||
|
||||
Element child = element.getChild("teavm");
|
||||
if (child == null) {
|
||||
child = new Element("teavm");
|
||||
element.addContent(child);
|
||||
}
|
||||
XmlSerializer.serializeInto(this, child, (accessor, bean) ->
|
||||
!accessor.getName().equals("isAllowRunningInParallel"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
|
||||
return new TeaVMDevServerSettingsEditor(getProject());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) {
|
||||
return new TeaVMDevServerRunState(environment, this);
|
||||
}
|
||||
|
||||
@Property
|
||||
@Tag
|
||||
public String getMainClass() {
|
||||
return mainClass;
|
||||
}
|
||||
|
||||
public void setMainClass(String mainClass) {
|
||||
this.mainClass = mainClass;
|
||||
}
|
||||
|
||||
@Property
|
||||
@Tag
|
||||
public String getJdkPath() {
|
||||
return jdkPath;
|
||||
}
|
||||
|
||||
public void setJdkPath(String jdkPath) {
|
||||
this.jdkPath = jdkPath;
|
||||
}
|
||||
|
||||
@Property
|
||||
@Tag
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Property
|
||||
@Tag
|
||||
public String getPathToFile() {
|
||||
return pathToFile;
|
||||
}
|
||||
|
||||
public void setPathToFile(String pathToFile) {
|
||||
this.pathToFile = pathToFile;
|
||||
}
|
||||
|
||||
@Property
|
||||
@Tag
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
@Property
|
||||
@Tag
|
||||
public boolean isIndicator() {
|
||||
return indicator;
|
||||
}
|
||||
|
||||
public void setIndicator(boolean indicator) {
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
@Property
|
||||
@Tag
|
||||
public boolean isAutomaticallyReloaded() {
|
||||
return automaticallyReloaded;
|
||||
}
|
||||
|
||||
public void setAutomaticallyReloaded(boolean automaticallyReloaded) {
|
||||
this.automaticallyReloaded = automaticallyReloaded;
|
||||
}
|
||||
|
||||
@Property
|
||||
@Tag
|
||||
public int getMaxHeap() {
|
||||
return maxHeap;
|
||||
}
|
||||
|
||||
public void setMaxHeap(int maxHeap) {
|
||||
this.maxHeap = maxHeap;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
import com.intellij.execution.configurations.ConfigurationFactory;
|
||||
import com.intellij.execution.configurations.ConfigurationTypeBase;
|
||||
import com.intellij.execution.configurations.RunConfiguration;
|
||||
import com.intellij.execution.configurations.RunConfigurationModule;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class TeaVMDevServerConfigurationType extends ConfigurationTypeBase {
|
||||
public TeaVMDevServerConfigurationType() {
|
||||
super("TeaVMDevServerConfiguration", "TeaVM development server", "TeaVM development server"
|
||||
+ "agent", IconLoader.getIcon("/teavm-16.png"));
|
||||
}
|
||||
|
||||
private final ConfigurationFactory factory = new ConfigurationFactory(this) {
|
||||
@NotNull
|
||||
@Override
|
||||
public RunConfiguration createTemplateConfiguration(@NotNull Project project) {
|
||||
return new TeaVMDevServerConfiguration(new RunConfigurationModule(project), this);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public ConfigurationFactory[] getConfigurationFactories() {
|
||||
return new ConfigurationFactory[] { factory };
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
import com.intellij.execution.DefaultExecutionResult;
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.ExecutionResult;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.configurations.RunProfileState;
|
||||
import com.intellij.execution.configurations.SearchScopeProvider;
|
||||
import com.intellij.execution.filters.TextConsoleBuilder;
|
||||
import com.intellij.execution.filters.TextConsoleBuilderFactory;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.runners.ProgramRunner;
|
||||
import com.intellij.execution.ui.ConsoleView;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import com.intellij.execution.util.JavaParametersUtil;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.OrderEnumerator;
|
||||
import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.teavm.idea.DaemonUtil;
|
||||
import org.teavm.idea.DevServerRunnerListener;
|
||||
|
||||
public class TeaVMDevServerRunState implements RunProfileState {
|
||||
private final TeaVMDevServerConfiguration configuration;
|
||||
private final TextConsoleBuilder consoleBuilder;
|
||||
|
||||
public TeaVMDevServerRunState(@NotNull ExecutionEnvironment environment,
|
||||
@NotNull TeaVMDevServerConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
|
||||
Project project = environment.getProject();
|
||||
GlobalSearchScope searchScope = SearchScopeProvider.createSearchScope(project, environment.getRunProfile());
|
||||
consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project, searchScope);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
|
||||
DevServerConfiguration config = new DevServerConfiguration();
|
||||
Module module = configuration.getConfigurationModule().getModule();
|
||||
|
||||
Sdk moduleSdk = JavaParametersUtil.createModuleJdk(module, true, configuration.getJdkPath());
|
||||
config.javaHome = moduleSdk.getHomePath();
|
||||
OrderEnumerator enumerator = OrderEnumerator.orderEntries(module).withoutSdk().recursively();
|
||||
config.classPath = Arrays.stream(enumerator.getClassesRoots())
|
||||
.map(this::path)
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(String[]::new);
|
||||
config.sourcePath = Arrays.stream(enumerator.getSourceRoots())
|
||||
.map(this::path)
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(String[]::new);
|
||||
config.pathToFile = configuration.getPathToFile();
|
||||
config.fileName = configuration.getFileName();
|
||||
config.port = configuration.getPort();
|
||||
config.indicator = configuration.isIndicator();
|
||||
config.autoReload = configuration.isAutomaticallyReloaded();
|
||||
config.mainClass = configuration.getMainClass();
|
||||
config.maxHeap = configuration.getMaxHeap();
|
||||
|
||||
try {
|
||||
ConsoleView console = consoleBuilder.getConsole();
|
||||
ProcessHandlerImpl processHandler = new ProcessHandlerImpl(config, console);
|
||||
console.attachToProcess(processHandler);
|
||||
processHandler.start();
|
||||
return new DefaultExecutionResult(console, processHandler);
|
||||
} catch (IOException e) {
|
||||
throw new ExecutionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String path(VirtualFile file) {
|
||||
while (file.getFileSystem() instanceof JarFileSystem) {
|
||||
file = ((JarFileSystem) file.getFileSystem()).getLocalByEntry(file);
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return file.getCanonicalPath();
|
||||
}
|
||||
|
||||
class ProcessHandlerImpl extends ProcessHandler implements DevServerRunnerListener {
|
||||
private DevServerConfiguration config;
|
||||
private ConsoleView console;
|
||||
private DevServerInfo info;
|
||||
|
||||
ProcessHandlerImpl(DevServerConfiguration config, ConsoleView console) {
|
||||
this.config = config;
|
||||
this.console = console;
|
||||
}
|
||||
|
||||
void start() throws IOException {
|
||||
info = DevServerRunner.start(DaemonUtil.detectClassPath().toArray(new String[0]), config, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void destroyProcessImpl() {
|
||||
info.process.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void detachProcessImpl() {
|
||||
try {
|
||||
info.server.stop();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean detachIsDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public OutputStream getProcessInput() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void error(String text) {
|
||||
console.print(text + System.lineSeparator(), ConsoleViewContentType.ERROR_OUTPUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String text) {
|
||||
console.print(text + System.lineSeparator(), ConsoleViewContentType.NORMAL_OUTPUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopped(int code) {
|
||||
notifyProcessTerminated(code);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.ExecutionResult;
|
||||
import com.intellij.execution.configurations.RunProfile;
|
||||
import com.intellij.execution.configurations.RunProfileState;
|
||||
import com.intellij.execution.configurations.RunnerSettings;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.runners.GenericProgramRunner;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class TeaVMDevServerRunner extends GenericProgramRunner<RunnerSettings> {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getRunnerId() {
|
||||
return "TeaVMDevServerRunner";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
|
||||
return profile instanceof TeaVMDevServerConfiguration;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected RunContentDescriptor doExecute(@NotNull RunProfileState state,
|
||||
@NotNull ExecutionEnvironment environment) throws ExecutionException {
|
||||
ExecutionResult executionResult = state.execute(environment.getExecutor(), environment.getRunner());
|
||||
if (executionResult == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver.ui;
|
||||
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import javax.swing.JComponent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.teavm.idea.devserver.TeaVMDevServerConfiguration;
|
||||
|
||||
public class TeaVMDevServerSettingsEditor extends SettingsEditor<TeaVMDevServerConfiguration> {
|
||||
private final Project project;
|
||||
private TeaVMDevServerSettingsPanel panel;
|
||||
|
||||
public TeaVMDevServerSettingsEditor(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetEditorFrom(@NotNull TeaVMDevServerConfiguration s) {
|
||||
if (panel == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
panel.load(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyEditorTo(@NotNull TeaVMDevServerConfiguration s) {
|
||||
if (panel == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
panel.save(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disposeEditor() {
|
||||
if (panel != null) {
|
||||
panel = null;
|
||||
}
|
||||
super.disposeEditor();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JComponent createEditor() {
|
||||
if (panel == null) {
|
||||
panel = new TeaVMDevServerSettingsPanel(project);
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright 2018 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.idea.devserver.ui;
|
||||
|
||||
import com.intellij.application.options.ModuleDescriptionsComboBox;
|
||||
import com.intellij.execution.configurations.ConfigurationUtil;
|
||||
import com.intellij.execution.ui.ConfigurationModuleSelector;
|
||||
import com.intellij.execution.ui.DefaultJreSelector;
|
||||
import com.intellij.execution.ui.JrePathEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.JavaCodeFragment;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.util.PsiMethodUtil;
|
||||
import com.intellij.ui.EditorTextFieldWithBrowseButton;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.text.DecimalFormat;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import org.teavm.idea.devserver.TeaVMDevServerConfiguration;
|
||||
|
||||
public class TeaVMDevServerSettingsPanel extends JPanel {
|
||||
private final JrePathEditor jrePathEditor;
|
||||
|
||||
private final ModuleDescriptionsComboBox moduleField;
|
||||
private final ConfigurationModuleSelector moduleSelector;
|
||||
|
||||
private EditorTextFieldWithBrowseButton mainClassField;
|
||||
|
||||
private JFormattedTextField portField;
|
||||
private JTextField pathToFileField;
|
||||
private JTextField fileNameField;
|
||||
private JCheckBox indicatorField;
|
||||
private JCheckBox autoReloadField;
|
||||
private JFormattedTextField maxHeapField;
|
||||
|
||||
public TeaVMDevServerSettingsPanel(Project project) {
|
||||
moduleField = new ModuleDescriptionsComboBox();
|
||||
moduleSelector = new ConfigurationModuleSelector(project, moduleField);
|
||||
|
||||
JavaCodeFragment.VisibilityChecker visibilityChecker = (declaration, place) -> {
|
||||
if (declaration instanceof PsiClass) {
|
||||
PsiClass cls = (PsiClass) declaration;
|
||||
if (ConfigurationUtil.MAIN_CLASS.value(cls) && PsiMethodUtil.findMainMethod(cls) != null
|
||||
|| place.getParent() != null && moduleSelector.findClass(cls.getQualifiedName()) != null) {
|
||||
return JavaCodeFragment.VisibilityChecker.Visibility.VISIBLE;
|
||||
}
|
||||
}
|
||||
return JavaCodeFragment.VisibilityChecker.Visibility.NOT_VISIBLE;
|
||||
};
|
||||
mainClassField = new EditorTextFieldWithBrowseButton(project, true, visibilityChecker);
|
||||
mainClassField.setButtonEnabled(true);
|
||||
|
||||
jrePathEditor = new JrePathEditor(DefaultJreSelector.fromSourceRootsDependencies(moduleField, mainClassField));
|
||||
|
||||
portField = new JFormattedTextField(new DecimalFormat("#0"));
|
||||
fileNameField = new JTextField();
|
||||
pathToFileField = new JTextField();
|
||||
indicatorField = new JCheckBox("Display indicator on a web page:");
|
||||
autoReloadField = new JCheckBox("Reload page automatically:");
|
||||
maxHeapField = new JFormattedTextField(new DecimalFormat("#0"));
|
||||
|
||||
initLayout();
|
||||
}
|
||||
|
||||
private void initLayout() {
|
||||
setLayout(new GridBagLayout());
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
|
||||
GridBagConstraints labelConstraints = new GridBagConstraints();
|
||||
labelConstraints.insets.right = 5;
|
||||
labelConstraints.anchor = GridBagConstraints.LINE_START;
|
||||
|
||||
GridBagConstraints constraints = new GridBagConstraints();
|
||||
constraints.gridwidth = GridBagConstraints.REMAINDER;
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
constraints.weightx = 1;
|
||||
constraints.insets.top = 4;
|
||||
constraints.insets.bottom = 4;
|
||||
|
||||
add(new JLabel("Main class:"), labelConstraints);
|
||||
add(mainClassField, constraints);
|
||||
|
||||
add(new JLabel("Use classpath of module:"), labelConstraints);
|
||||
add(moduleField, constraints);
|
||||
|
||||
add(jrePathEditor, constraints);
|
||||
|
||||
add(new JLabel("Port:"), labelConstraints);
|
||||
add(portField, constraints);
|
||||
|
||||
add(new JLabel("File name:"), labelConstraints);
|
||||
add(fileNameField, constraints);
|
||||
|
||||
add(new JLabel("Path to file:"), labelConstraints);
|
||||
add(pathToFileField, constraints);
|
||||
|
||||
add(indicatorField, constraints);
|
||||
add(autoReloadField, constraints);
|
||||
|
||||
add(new JLabel("Server heap limit:"), labelConstraints);
|
||||
add(maxHeapField, constraints);
|
||||
}
|
||||
|
||||
public void load(TeaVMDevServerConfiguration configuration) {
|
||||
mainClassField.setText(configuration.getMainClass());
|
||||
moduleSelector.reset(configuration);
|
||||
jrePathEditor.setPathOrName(configuration.getJdkPath(), false);
|
||||
fileNameField.setText(configuration.getFileName());
|
||||
pathToFileField.setText(configuration.getPathToFile());
|
||||
indicatorField.setSelected(configuration.isIndicator());
|
||||
autoReloadField.setSelected(configuration.isAutomaticallyReloaded());
|
||||
maxHeapField.setText(Integer.toString(configuration.getMaxHeap()));
|
||||
portField.setText(Integer.toString(configuration.getPort()));
|
||||
}
|
||||
|
||||
public void save(TeaVMDevServerConfiguration configuration) {
|
||||
configuration.setMainClass(mainClassField.getText());
|
||||
moduleSelector.applyTo(configuration);
|
||||
configuration.setJdkPath(jrePathEditor.getJrePathOrName());
|
||||
configuration.setFileName(fileNameField.getText());
|
||||
configuration.setPathToFile(pathToFileField.getText());
|
||||
configuration.setIndicator(indicatorField.isSelected());
|
||||
configuration.setAutomaticallyReloaded(autoReloadField.isSelected());
|
||||
configuration.setMaxHeap(Integer.parseInt(maxHeapField.getText()));
|
||||
configuration.setPort(Integer.parseInt(portField.getText()));
|
||||
}
|
||||
}
|
|
@ -110,6 +110,9 @@ public class TeaVMMavenImporter extends MavenImporter {
|
|||
}
|
||||
|
||||
TeaVMJpsConfiguration configuration = facet.getConfiguration().getState();
|
||||
if (justCreated) {
|
||||
configuration.setSkipped(true);
|
||||
}
|
||||
|
||||
for (Element child : source.getChildren()) {
|
||||
switch (child.getName()) {
|
||||
|
|
|
@ -17,7 +17,6 @@ package org.teavm.idea.ui;
|
|||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import javax.swing.JComponent;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -60,7 +59,7 @@ public class TeaVMConfigurable implements Configurable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
public void apply() {
|
||||
panel.save(configuration);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ package org.teavm.idea.ui;
|
|||
|
||||
import com.intellij.facet.ui.FacetEditorTab;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import javax.swing.JComponent;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -48,7 +47,7 @@ public class TeaVMFacetEditorTab extends FacetEditorTab {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
public void apply() {
|
||||
configurable.apply();
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
<configurationType implementation="org.teavm.idea.debug.TeaVMDebugConfigurationType"/>
|
||||
<programRunner implementation="org.teavm.idea.debug.TeaVMDebugRunner"/>
|
||||
|
||||
<configurationType implementation="org.teavm.idea.devserver.TeaVMDevServerConfigurationType"/>
|
||||
<programRunner implementation="org.teavm.idea.devserver.TeaVMDevServerRunner"/>
|
||||
|
||||
<applicationConfigurable instance="org.teavm.idea.ui.TeaVMSettingsEditorTab"
|
||||
id="project.teavm.settings"
|
||||
displayName="TeaVM compiler"
|
||||
|
|
Loading…
Reference in New Issue
Block a user