mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-02 13:24:11 -08:00
gradle: implement dev server task
This commit is contained in:
parent
7341fb38a6
commit
bbd02b0067
|
@ -3,7 +3,6 @@
|
|||
<component name="CheckStyle-IDEA" serialisationVersion="2">
|
||||
<checkstyleVersion>8.41.1</checkstyleVersion>
|
||||
<scanScope>JavaOnlyWithTests</scanScope>
|
||||
<option name="thirdPartyClasspath" />
|
||||
<option name="activeLocationIds">
|
||||
<option value="c65b2ab0-cb40-4423-befb-a37d514deee5" />
|
||||
</option>
|
||||
|
|
|
@ -16,5 +16,4 @@
|
|||
package org.teavm.common.json;
|
||||
|
||||
public abstract class JsonNumericValue extends JsonValue {
|
||||
public abstract double asNumber();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.io.IOException;
|
|||
import java.io.Reader;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class JsonParser {
|
||||
private JsonConsumer consumer;
|
||||
|
@ -32,6 +33,8 @@ public class JsonParser {
|
|||
}
|
||||
|
||||
public void parse(Reader reader) throws IOException {
|
||||
lineNumber = 0;
|
||||
columnNumber = 0;
|
||||
lastChar = reader.read();
|
||||
skipWhitespaces(reader);
|
||||
if (lastChar == -1) {
|
||||
|
@ -412,4 +415,8 @@ public class JsonParser {
|
|||
private static boolean isDigit(int c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
public static JsonParser ofValue(Consumer<JsonValue> consumer) {
|
||||
return new JsonParser(new JsonVisitingConsumer(JsonValueParserVisitor.create(consumer)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,4 +27,8 @@ public abstract class JsonValue {
|
|||
public long asIntNumber() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public double asNumber() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.teavm.common.json;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
public abstract class JsonValueParserVisitor extends JsonAllErrorVisitor {
|
||||
private JsonValue deferred;
|
||||
|
||||
public abstract void consume(JsonValue value);
|
||||
|
||||
public static JsonValueParserVisitor create(Consumer<JsonValue> consumer) {
|
||||
|
@ -32,7 +34,7 @@ public abstract class JsonValueParserVisitor extends JsonAllErrorVisitor {
|
|||
@Override
|
||||
public JsonVisitor object(JsonErrorReporter reporter) {
|
||||
var jsonObject = new JsonObjectValue();
|
||||
consume(jsonObject);
|
||||
deferred = jsonObject;
|
||||
return new JsonAllErrorVisitor() {
|
||||
@Override
|
||||
public JsonVisitor property(JsonErrorReporter reporter, String name) {
|
||||
|
@ -47,12 +49,17 @@ public abstract class JsonValueParserVisitor extends JsonAllErrorVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JsonVisitor array(JsonErrorReporter reporter) {
|
||||
var jsonArray = new JsonArrayValue();
|
||||
consume(jsonArray);
|
||||
return new JsonAllErrorVisitor() {
|
||||
public void end(JsonErrorReporter reporter) {
|
||||
super.end(reporter);
|
||||
var value = deferred;
|
||||
deferred = null;
|
||||
consume(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonVisitor array(JsonErrorReporter reporter) {
|
||||
var jsonArray = new JsonArrayValue();
|
||||
deferred = jsonArray;
|
||||
return new JsonValueParserVisitor() {
|
||||
@Override
|
||||
public void consume(JsonValue value) {
|
||||
|
@ -60,8 +67,6 @@ public abstract class JsonValueParserVisitor extends JsonAllErrorVisitor {
|
|||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stringValue(JsonErrorReporter reporter, String value) {
|
||||
|
|
|
@ -22,9 +22,17 @@ plugins {
|
|||
id("org.teavm")
|
||||
}
|
||||
|
||||
configurations {
|
||||
create("teavmCli")
|
||||
create("teavmClasslib")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
teavm(teavm.libs.jsoApis)
|
||||
compileOnly("jakarta.servlet:jakarta.servlet-api:6.0.0")
|
||||
|
||||
"teavmCli"("org.teavm:teavm-cli:0.10.0-SNAPSHOT")
|
||||
"teavmClasslib"("org.teavm:teavm-classlib:0.10.0-SNAPSHOT")
|
||||
}
|
||||
|
||||
teavm.js {
|
||||
|
@ -33,3 +41,14 @@ teavm.js {
|
|||
sourceMap = true
|
||||
sourceFilePolicy = SourceFilePolicy.LINK_LOCAL_FILES
|
||||
}
|
||||
|
||||
tasks.register<JavaExec>("runCli") {
|
||||
classpath(configurations["teavmCli"])
|
||||
mainClass = "org.teavm.cli.devserver.TeaVMDevServerRunner"
|
||||
args = listOf("--json-interface", "--no-watch", "-p",
|
||||
layout.buildDirectory.dir("classes/java/teavm").get().asFile.absolutePath,
|
||||
) + configurations["teavmClasslib"].flatMap { listOf("-p", it.absolutePath) } + listOf(
|
||||
"--", "org.teavm.samples.hello.Client"
|
||||
)
|
||||
println(args)
|
||||
}
|
|
@ -24,6 +24,7 @@ public final class PiCalculator {
|
|||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("hello1");
|
||||
var start = System.currentTimeMillis();
|
||||
int n = Integer.parseInt(args[0]);
|
||||
int j = 0;
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -530,7 +529,7 @@ public class IncrementalCBuilder {
|
|||
}
|
||||
|
||||
private void fireBuildComplete(TeaVM vm) {
|
||||
SimpleBuildResult result = new SimpleBuildResult(vm, Collections.emptyList());
|
||||
SimpleBuildResult result = new SimpleBuildResult(vm);
|
||||
for (BuilderListener listener : listeners) {
|
||||
listener.compilationComplete(result);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ dependencies {
|
|||
implementation(project(":tools:devserver"))
|
||||
implementation(project(":tools:c-incremental"))
|
||||
implementation(libs.commons.cli)
|
||||
implementation(libs.jetty.server)
|
||||
|
||||
runtimeOnly(project(":classlib"))
|
||||
runtimeOnly(project(":metaprogramming:impl"))
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2024 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.devserver;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import org.teavm.common.json.JsonValue;
|
||||
import org.teavm.devserver.DevServer;
|
||||
|
||||
public class JsonCommandReader implements Consumer<JsonValue> {
|
||||
private DevServer devServer;
|
||||
|
||||
public JsonCommandReader(DevServer devServer) {
|
||||
this.devServer = devServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(JsonValue jsonValue) {
|
||||
var obj = jsonValue.asObject();
|
||||
var type = obj.get("type").asString();
|
||||
switch (type) {
|
||||
case "build":
|
||||
devServer.buildProject();
|
||||
break;
|
||||
case "cancel":
|
||||
devServer.cancelBuild();
|
||||
break;
|
||||
case "stop":
|
||||
System.exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright 2024 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.devserver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.teavm.common.JsonUtil;
|
||||
import org.teavm.devserver.DevServerListener;
|
||||
import org.teavm.diagnostics.DefaultProblemTextConsumer;
|
||||
import org.teavm.tooling.TeaVMProblemRenderer;
|
||||
import org.teavm.tooling.TeaVMToolLog;
|
||||
import org.teavm.tooling.builder.BuildResult;
|
||||
|
||||
public class JsonCommandWriter implements TeaVMToolLog, DevServerListener, Logger {
|
||||
private PrintWriter writer = new PrintWriter(System.out, false, StandardCharsets.UTF_8);
|
||||
|
||||
@Override
|
||||
public void info(String text) {
|
||||
writeMessage("info", text, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text) {
|
||||
writeMessage("debug", text, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text) {
|
||||
writeMessage("warning", text, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text) {
|
||||
writeMessage("error", text, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String text, Throwable e) {
|
||||
writeMessage("info", text, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String text, Throwable e) {
|
||||
writeMessage("debug", text, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(String text, Throwable e) {
|
||||
writeMessage("warning", text, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String text, Throwable e) {
|
||||
writeMessage("error", text, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "dev-server";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Object... objects) {
|
||||
writeMessage("warning", format(s, objects), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Throwable throwable) {
|
||||
writeMessage("warning", "", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Throwable throwable) {
|
||||
writeMessage("warning", s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Object... objects) {
|
||||
writeMessage("info", format(s, objects), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Throwable throwable) {
|
||||
writeMessage("info", "", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDebugEnabled(boolean b) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Object... objects) {
|
||||
writeMessage("debug", format(s, objects), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, long l) {
|
||||
writeMessage("debug", format(s, new Object[] { l }), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Throwable throwable) {
|
||||
writeMessage("debug", "", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger(String s) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignore(Throwable throwable) {
|
||||
}
|
||||
|
||||
private String format(String message, Object[] args) {
|
||||
var index = 0;
|
||||
var sb = new StringBuilder();
|
||||
for (var i = 0; i < args.length; ++i) {
|
||||
var next = message.indexOf("{}", index);
|
||||
if (next < 0) {
|
||||
break;
|
||||
}
|
||||
sb.append(message, index, next);
|
||||
sb.append(args[i]);
|
||||
index = next + 2;
|
||||
}
|
||||
sb.append(message, index, message.length());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private synchronized void writeMessage(String level, String message, Throwable throwable) {
|
||||
try {
|
||||
writer.append("{\"type\":\"log\",\"level\":\"").append(level).append("\",\"message\":\"");
|
||||
JsonUtil.writeEscapedString(writer, message);
|
||||
writer.append("\"");
|
||||
if (throwable != null) {
|
||||
writer.append(",\"throwable\":\"");
|
||||
var throwableBuffer = new StringWriter();
|
||||
var throwableWriter = new PrintWriter(throwableBuffer);
|
||||
throwable.printStackTrace(throwableWriter);
|
||||
JsonUtil.writeEscapedString(writer, throwableBuffer.toString());
|
||||
writer.append("\"");
|
||||
}
|
||||
writer.append("}");
|
||||
writer.println();
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void compilationStarted() {
|
||||
writer.append("{\"type\":\"compilation-started\"}");
|
||||
writer.println();
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void compilationProgress(double progress) {
|
||||
writer.append("{\"type\":\"compilation-progress\",\"progress\":").append(String.valueOf(progress))
|
||||
.append("}");
|
||||
writer.println();
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void compilationComplete(BuildResult result) {
|
||||
var consumer = new DefaultProblemTextConsumer();
|
||||
try {
|
||||
writer.append("{\"type\":\"compilation-complete\"");
|
||||
if (result != null && !result.getProblems().getProblems().isEmpty()) {
|
||||
writer.append(",\"problems\":[");
|
||||
for (var i = 0; i < result.getProblems().getProblems().size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",");
|
||||
}
|
||||
var problem = result.getProblems().getProblems().get(i);
|
||||
writer.append("{\"severity\":");
|
||||
switch (problem.getSeverity()) {
|
||||
case ERROR:
|
||||
writer.append("\"error\"");
|
||||
break;
|
||||
case WARNING:
|
||||
writer.append("\"warning\"");
|
||||
break;
|
||||
}
|
||||
writer.append(",\"location\":\"");
|
||||
var sb = new StringBuilder();
|
||||
TeaVMProblemRenderer.renderCallStack(result.getCallGraph(), problem.getLocation(), sb);
|
||||
JsonUtil.writeEscapedString(writer, sb.toString());
|
||||
writer.append("\",\"message\":\"");
|
||||
problem.render(consumer);
|
||||
JsonUtil.writeEscapedString(writer, consumer.getText());
|
||||
writer.append("\"}");
|
||||
}
|
||||
writer.append("]");
|
||||
}
|
||||
writer.append("}");
|
||||
writer.println();
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void compilationCancelled() {
|
||||
writer.append("{\"type\":\"compilation-cancelled\"}");
|
||||
writer.println();
|
||||
writer.flush();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 Alexey Andreev.
|
||||
* Copyright 2024 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,9 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.cli;
|
||||
package org.teavm.cli.devserver;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
|
@ -23,6 +29,8 @@ import org.apache.commons.cli.HelpFormatter;
|
|||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.teavm.common.json.JsonParser;
|
||||
import org.teavm.devserver.DevServer;
|
||||
import org.teavm.tooling.ConsoleTeaVMToolLog;
|
||||
|
||||
|
@ -30,6 +38,7 @@ public final class TeaVMDevServerRunner {
|
|||
private static Options options = new Options();
|
||||
private DevServer devServer;
|
||||
private CommandLine commandLine;
|
||||
private JsonCommandWriter jsonWriter;
|
||||
|
||||
static {
|
||||
setupOptions();
|
||||
|
@ -56,10 +65,21 @@ public final class TeaVMDevServerRunner {
|
|||
.build());
|
||||
options.addOption(Option.builder("s")
|
||||
.argName("sourcepath")
|
||||
.hasArg()
|
||||
.hasArgs()
|
||||
.desc("source path (either directory or jar file which contains source code)")
|
||||
.longOpt("sourcepath")
|
||||
.build());
|
||||
options.addOption(Option.builder()
|
||||
.argName("classnames")
|
||||
.hasArgs()
|
||||
.desc("list of classes that should be preserved during the build (e.g. to use with reflection)")
|
||||
.longOpt("preserved-classes")
|
||||
.build());
|
||||
options.addOption(Option.builder()
|
||||
.valueSeparator()
|
||||
.hasArgs()
|
||||
.longOpt("property")
|
||||
.build());
|
||||
options.addOption(Option.builder()
|
||||
.argName("number")
|
||||
.hasArg()
|
||||
|
@ -94,6 +114,14 @@ public final class TeaVMDevServerRunner {
|
|||
.desc("delegate requests from path")
|
||||
.longOpt("proxy-path")
|
||||
.build());
|
||||
options.addOption(Option.builder()
|
||||
.desc("don't watch file system changes")
|
||||
.longOpt("no-watch")
|
||||
.build());
|
||||
options.addOption(Option.builder()
|
||||
.desc("JSON interface over stdout")
|
||||
.longOpt("json-interface")
|
||||
.build());
|
||||
}
|
||||
|
||||
private TeaVMDevServerRunner(CommandLine commandLine) {
|
||||
|
@ -117,7 +145,16 @@ public final class TeaVMDevServerRunner {
|
|||
|
||||
TeaVMDevServerRunner runner = new TeaVMDevServerRunner(commandLine);
|
||||
runner.parseArguments();
|
||||
runner.runAll();
|
||||
runner.devServer.start();
|
||||
if (runner.jsonWriter != null) {
|
||||
runner.readStdinCommands();
|
||||
} else {
|
||||
try {
|
||||
runner.devServer.awaitServer();
|
||||
} catch (InterruptedException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseArguments() {
|
||||
|
@ -128,7 +165,6 @@ public final class TeaVMDevServerRunner {
|
|||
devServer.setIndicator(commandLine.hasOption("indicator"));
|
||||
devServer.setDeobfuscateStack(commandLine.hasOption("deobfuscate-stack"));
|
||||
devServer.setReloadedAutomatically(commandLine.hasOption("auto-reload"));
|
||||
devServer.setLog(new ConsoleTeaVMToolLog(commandLine.hasOption('v')));
|
||||
if (commandLine.hasOption("port")) {
|
||||
try {
|
||||
devServer.setPort(Integer.parseInt(commandLine.getOptionValue("port")));
|
||||
|
@ -138,12 +174,29 @@ public final class TeaVMDevServerRunner {
|
|||
}
|
||||
}
|
||||
|
||||
var properties = commandLine.getOptionProperties("property");
|
||||
for (var property : properties.stringPropertyNames()) {
|
||||
devServer.getProperties().put(property, properties.getProperty(property));
|
||||
}
|
||||
|
||||
if (commandLine.hasOption("preserved-classes")) {
|
||||
devServer.getPreservedClasses().addAll(List.of(commandLine.getOptionValues("preserved-classes")));
|
||||
}
|
||||
|
||||
if (commandLine.hasOption("proxy-url")) {
|
||||
devServer.setProxyUrl(commandLine.getOptionValue("proxy-url"));
|
||||
}
|
||||
if (commandLine.hasOption("proxy-path")) {
|
||||
devServer.setProxyPath(commandLine.getOptionValue("proxy-path"));
|
||||
}
|
||||
if (commandLine.hasOption("no-watch")) {
|
||||
devServer.setFileSystemWatched(false);
|
||||
}
|
||||
if (commandLine.hasOption("json-interface")) {
|
||||
setupJsonInterface(devServer);
|
||||
} else {
|
||||
devServer.setLog(new ConsoleTeaVMToolLog(commandLine.hasOption('v')));
|
||||
}
|
||||
|
||||
String[] args = commandLine.getArgs();
|
||||
if (args.length != 1) {
|
||||
|
@ -175,8 +228,29 @@ public final class TeaVMDevServerRunner {
|
|||
}
|
||||
}
|
||||
|
||||
private void runAll() {
|
||||
devServer.start();
|
||||
private void setupJsonInterface(DevServer devServer) {
|
||||
jsonWriter = new JsonCommandWriter();
|
||||
devServer.setLog(jsonWriter);
|
||||
devServer.addListener(jsonWriter);
|
||||
devServer.setCompileOnStartup(false);
|
||||
devServer.setLogBuildErrors(false);
|
||||
Log.setLog(jsonWriter);
|
||||
}
|
||||
|
||||
private void readStdinCommands() {
|
||||
var commandReader = new JsonCommandReader(devServer);
|
||||
var parser = JsonParser.ofValue(commandReader);
|
||||
try (var reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
|
||||
while (true) {
|
||||
var command = reader.readLine();
|
||||
if (command == null) {
|
||||
break;
|
||||
}
|
||||
parser.parse(new StringReader(command));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void printUsage() {
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package org.teavm.tooling.builder;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.diagnostics.ProblemProvider;
|
||||
|
||||
|
@ -23,10 +22,4 @@ public interface BuildResult {
|
|||
CallGraph getCallGraph();
|
||||
|
||||
ProblemProvider getProblems();
|
||||
|
||||
Collection<String> getUsedResources();
|
||||
|
||||
Collection<String> getClasses();
|
||||
|
||||
Collection<String> getGeneratedFiles();
|
||||
}
|
||||
|
|
|
@ -22,10 +22,8 @@ import java.net.URL;
|
|||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.backend.javascript.JSModuleType;
|
||||
import org.teavm.backend.wasm.render.WasmBinaryVersion;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
|
@ -287,12 +285,8 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
|||
throw new BuildException(e);
|
||||
}
|
||||
|
||||
var generatedFiles = tool.getGeneratedFiles().stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return new InProcessBuildResult(tool.getDependencyInfo().getCallGraph(),
|
||||
tool.getProblemProvider(), tool.getClasses(), tool.getUsedResources(), generatedFiles);
|
||||
tool.getProblemProvider());
|
||||
}
|
||||
|
||||
private URLClassLoader buildClassLoader() {
|
||||
|
@ -310,17 +304,10 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
|||
static class InProcessBuildResult implements BuildResult {
|
||||
private CallGraph callGraph;
|
||||
private ProblemProvider problemProvider;
|
||||
private Collection<String> classes;
|
||||
private Collection<String> usedResources;
|
||||
private Collection<String> generatedFiles;
|
||||
|
||||
InProcessBuildResult(CallGraph callGraph, ProblemProvider problemProvider,
|
||||
Collection<String> classes, Collection<String> usedResources, Collection<String> generatedFiles) {
|
||||
InProcessBuildResult(CallGraph callGraph, ProblemProvider problemProvider) {
|
||||
this.callGraph = callGraph;
|
||||
this.problemProvider = problemProvider;
|
||||
this.classes = classes;
|
||||
this.usedResources = usedResources;
|
||||
this.generatedFiles = generatedFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -332,20 +319,5 @@ public class InProcessBuildStrategy implements BuildStrategy {
|
|||
public ProblemProvider getProblems() {
|
||||
return problemProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getClasses() {
|
||||
return classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getUsedResources() {
|
||||
return usedResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getGeneratedFiles() {
|
||||
return generatedFiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package org.teavm.tooling.builder;
|
|||
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import org.teavm.backend.javascript.JSModuleType;
|
||||
|
@ -246,21 +245,6 @@ public class RemoteBuildStrategy implements BuildStrategy {
|
|||
public ProblemProvider getProblems() {
|
||||
return problems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getUsedResources() {
|
||||
return response.usedResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getClasses() {
|
||||
return response.classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getGeneratedFiles() {
|
||||
return response.generatedFiles;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -15,21 +15,15 @@
|
|||
*/
|
||||
package org.teavm.tooling.builder;
|
||||
|
||||
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.vm.TeaVM;
|
||||
|
||||
public class SimpleBuildResult implements BuildResult {
|
||||
private TeaVM vm;
|
||||
private List<String> generatedFiles;
|
||||
private Collection<String> usedResources;
|
||||
|
||||
public SimpleBuildResult(TeaVM vm, List<String> generatedFiles) {
|
||||
public SimpleBuildResult(TeaVM vm) {
|
||||
this.vm = vm;
|
||||
this.generatedFiles = generatedFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,22 +35,4 @@ public class SimpleBuildResult implements BuildResult {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,11 +186,6 @@ public class BuildDaemon extends UnicastRemoteObject implements RemoteBuildServi
|
|||
response.callGraph = tool.getDependencyInfo().getCallGraph();
|
||||
response.problems.addAll(tool.getProblemProvider().getProblems());
|
||||
response.severeProblems.addAll(tool.getProblemProvider().getSevereProblems());
|
||||
response.classes.addAll(tool.getClasses());
|
||||
response.usedResources.addAll(tool.getUsedResources());
|
||||
response.generatedFiles.addAll(tool.getGeneratedFiles().stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
return response;
|
||||
|
|
|
@ -17,9 +17,7 @@ package org.teavm.tooling.daemon;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.diagnostics.Problem;
|
||||
|
||||
|
@ -27,8 +25,5 @@ public class RemoteBuildResponse implements Serializable {
|
|||
public CallGraph callGraph;
|
||||
public final List<Problem> problems = new ArrayList<>();
|
||||
public final List<Problem> severeProblems = new ArrayList<>();
|
||||
public final Set<String> usedResources = new HashSet<>();
|
||||
public final Set<String> classes = new HashSet<>();
|
||||
public final Set<String> generatedFiles = new HashSet<>();
|
||||
public Throwable exception;
|
||||
}
|
||||
|
|
|
@ -98,16 +98,22 @@ public class FileSystemWatcher {
|
|||
return !changedFiles.isEmpty() || pollNow();
|
||||
}
|
||||
|
||||
public void pollChanges() throws IOException {
|
||||
while (pollNow()) {
|
||||
// continue polling
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForChange(int timeout) throws InterruptedException, IOException {
|
||||
if (!hasChanges()) {
|
||||
take();
|
||||
}
|
||||
if (timeout > 0) {
|
||||
while (poll(timeout)) {
|
||||
// continue polling
|
||||
}
|
||||
while (pollNow()) {
|
||||
// continue polling
|
||||
}
|
||||
pollChanges();
|
||||
}
|
||||
|
||||
public List<File> grabChangedFiles() {
|
||||
|
|
|
@ -86,6 +86,7 @@ import org.teavm.parsing.resource.ResourceClassHolderMapper;
|
|||
import org.teavm.tooling.EmptyTeaVMToolLog;
|
||||
import org.teavm.tooling.TeaVMProblemRenderer;
|
||||
import org.teavm.tooling.TeaVMToolLog;
|
||||
import org.teavm.tooling.builder.BuildResult;
|
||||
import org.teavm.tooling.builder.SimpleBuildResult;
|
||||
import org.teavm.tooling.util.FileSystemWatcher;
|
||||
import org.teavm.vm.MemoryBuildTarget;
|
||||
|
@ -119,6 +120,8 @@ public class CodeServlet extends HttpServlet {
|
|||
private String proxyProtocol;
|
||||
private int proxyPort;
|
||||
private String proxyBaseUrl;
|
||||
private Map<String, String> properties = new LinkedHashMap<>();
|
||||
private List<String> preservedClasses = new ArrayList<>();
|
||||
|
||||
private Map<String, Supplier<InputStream>> sourceFileCache = new HashMap<>();
|
||||
|
||||
|
@ -148,6 +151,9 @@ public class CodeServlet extends HttpServlet {
|
|||
private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable();
|
||||
private InMemorySymbolTable variableSymbolTable = new InMemorySymbolTable();
|
||||
private ReferenceCache referenceCache = new ReferenceCache();
|
||||
private boolean fileSystemWatched = true;
|
||||
private boolean compileOnStartup = true;
|
||||
private boolean logBuildErrors = true;
|
||||
|
||||
public CodeServlet(String mainClass, String[] classPath) {
|
||||
this.mainClass = mainClass;
|
||||
|
@ -201,6 +207,26 @@ public class CodeServlet extends HttpServlet {
|
|||
this.proxyPath = normalizePath(proxyPath);
|
||||
}
|
||||
|
||||
public void setFileSystemWatched(boolean fileSystemWatched) {
|
||||
this.fileSystemWatched = fileSystemWatched;
|
||||
}
|
||||
|
||||
public void setCompileOnStartup(boolean compileOnStartup) {
|
||||
this.compileOnStartup = compileOnStartup;
|
||||
}
|
||||
|
||||
public List<String> getPreservedClasses() {
|
||||
return preservedClasses;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setLogBuildErrors(boolean logBuildErrors) {
|
||||
this.logBuildErrors = logBuildErrors;
|
||||
}
|
||||
|
||||
public void addProgressHandler(ProgressHandler handler) {
|
||||
synchronized (progressHandlers) {
|
||||
progressHandlers.add(handler);
|
||||
|
@ -241,12 +267,16 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
public void buildProject() {
|
||||
if (buildThread == null) {
|
||||
runCompilerThread();
|
||||
} else {
|
||||
synchronized (statusLock) {
|
||||
if (waiting) {
|
||||
buildThread.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelBuild() {
|
||||
synchronized (statusLock) {
|
||||
|
@ -617,7 +647,7 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
stopped = true;
|
||||
synchronized (statusLock) {
|
||||
if (waiting) {
|
||||
if (buildThread != null && waiting) {
|
||||
buildThread.interrupt();
|
||||
}
|
||||
}
|
||||
|
@ -626,7 +656,13 @@ public class CodeServlet extends HttpServlet {
|
|||
@Override
|
||||
public void init() throws ServletException {
|
||||
super.init();
|
||||
Thread thread = new Thread(this::runTeaVM);
|
||||
if (compileOnStartup) {
|
||||
runCompilerThread();
|
||||
}
|
||||
}
|
||||
|
||||
private void runCompilerThread() {
|
||||
var thread = new Thread(this::runTeaVM);
|
||||
thread.setName("TeaVM compiler");
|
||||
thread.start();
|
||||
buildThread = thread;
|
||||
|
@ -726,8 +762,13 @@ public class CodeServlet extends HttpServlet {
|
|||
try {
|
||||
initBuilder();
|
||||
|
||||
var hasJob = true;
|
||||
while (!stopped) {
|
||||
if (hasJob) {
|
||||
buildOnce();
|
||||
} else {
|
||||
emptyBuild();
|
||||
}
|
||||
|
||||
if (stopped) {
|
||||
break;
|
||||
|
@ -737,11 +778,22 @@ public class CodeServlet extends HttpServlet {
|
|||
synchronized (statusLock) {
|
||||
waiting = true;
|
||||
}
|
||||
if (fileSystemWatched) {
|
||||
watcher.waitForChange(750);
|
||||
log.info("Changes detected. Recompiling.");
|
||||
} else {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
watcher.pollChanges();
|
||||
}
|
||||
synchronized (statusLock) {
|
||||
waiting = false;
|
||||
}
|
||||
log.info("Changes detected. Recompiling.");
|
||||
} catch (InterruptedException e) {
|
||||
if (stopped) {
|
||||
break;
|
||||
|
@ -760,6 +812,7 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
classSource.evict(staleClasses);
|
||||
hasJob = !staleClasses.isEmpty();
|
||||
}
|
||||
log.info("Build process stopped");
|
||||
} catch (Throwable e) {
|
||||
|
@ -836,6 +889,10 @@ public class CodeServlet extends HttpServlet {
|
|||
vm.setProgressListener(progressListener);
|
||||
vm.setProgramCache(programCache);
|
||||
vm.installPlugins();
|
||||
for (var className : preservedClasses) {
|
||||
vm.preserveType(className);
|
||||
}
|
||||
vm.getProperties().putAll(properties);
|
||||
|
||||
vm.setLastKnownClasses(lastReachedClasses);
|
||||
vm.setEntryPoint(mainClass);
|
||||
|
@ -850,6 +907,12 @@ public class CodeServlet extends HttpServlet {
|
|||
postBuild(vm, startTime);
|
||||
}
|
||||
|
||||
private void emptyBuild() {
|
||||
fireBuildStarted();
|
||||
log.info("No files changed, nothing to do");
|
||||
fireBuildCompleteWithResult(null);
|
||||
}
|
||||
|
||||
private ClassReaderSource packClasses(ClassReaderSource source, Collection<? extends String> classNames) {
|
||||
MemoryCachedClassReaderSource packedSource = createCachedSource();
|
||||
packedSource.setProvider(source::get);
|
||||
|
@ -912,7 +975,6 @@ 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();
|
||||
|
@ -926,7 +988,10 @@ public class CodeServlet extends HttpServlet {
|
|||
reportCompilationComplete(false);
|
||||
}
|
||||
printStats(vm, startTime);
|
||||
if (logBuildErrors) {
|
||||
TeaVMProblemRenderer.describeProblems(vm, log);
|
||||
}
|
||||
fireBuildComplete(vm);
|
||||
} else {
|
||||
log.info("Build cancelled");
|
||||
fireBuildCancelled();
|
||||
|
@ -1056,9 +1121,12 @@ public class CodeServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
private void fireBuildComplete(TeaVM vm) {
|
||||
SimpleBuildResult result = new SimpleBuildResult(vm, new ArrayList<>(buildTarget.getNames()));
|
||||
for (DevServerListener listener : listeners) {
|
||||
listener.compilationComplete(result);
|
||||
fireBuildCompleteWithResult(new SimpleBuildResult(vm));
|
||||
}
|
||||
|
||||
private void fireBuildCompleteWithResult(BuildResult buildResult) {
|
||||
for (var listener : listeners) {
|
||||
listener.compilationComplete(buildResult);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1089,7 +1157,7 @@ public class CodeServlet extends HttpServlet {
|
|||
|
||||
@Override
|
||||
public TeaVMProgressFeedback progressReached(int progress) {
|
||||
if (indicator) {
|
||||
if (indicator || !listeners.isEmpty()) {
|
||||
int current = start + Math.min(progress, phaseLimit) * (end - start) / phaseLimit;
|
||||
if (current != last) {
|
||||
if (current - last > 10 || System.currentTimeMillis() - lastTime > 100) {
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
package org.teavm.devserver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
|
@ -32,9 +34,14 @@ public class DevServer {
|
|||
private boolean indicator;
|
||||
private boolean deobfuscateStack;
|
||||
private boolean reloadedAutomatically;
|
||||
private boolean fileSystemWatched = true;
|
||||
private TeaVMToolLog log;
|
||||
private CodeServlet servlet;
|
||||
private List<DevServerListener> listeners = new ArrayList<>();
|
||||
private Map<String, String> properties = new LinkedHashMap<>();
|
||||
private List<String> preservedClasses = new ArrayList<>();
|
||||
private boolean compileOnStartup;
|
||||
private boolean logBuildErrors = true;
|
||||
|
||||
private Server server;
|
||||
private int port = 9090;
|
||||
|
@ -88,6 +95,10 @@ public class DevServer {
|
|||
this.reloadedAutomatically = reloadedAutomatically;
|
||||
}
|
||||
|
||||
public void setFileSystemWatched(boolean fileSystemWatched) {
|
||||
this.fileSystemWatched = fileSystemWatched;
|
||||
}
|
||||
|
||||
public void setProxyUrl(String proxyUrl) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
}
|
||||
|
@ -100,6 +111,18 @@ public class DevServer {
|
|||
return sourcePath;
|
||||
}
|
||||
|
||||
public void setCompileOnStartup(boolean compileOnStartup) {
|
||||
this.compileOnStartup = compileOnStartup;
|
||||
}
|
||||
|
||||
public List<String> getPreservedClasses() {
|
||||
return preservedClasses;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
servlet.invalidateCache();
|
||||
}
|
||||
|
@ -116,6 +139,10 @@ public class DevServer {
|
|||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void setLogBuildErrors(boolean logBuildErrors) {
|
||||
this.logBuildErrors = logBuildErrors;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
server = new Server();
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
|
@ -138,6 +165,11 @@ public class DevServer {
|
|||
servlet.setDebugPort(debugPort);
|
||||
servlet.setProxyUrl(proxyUrl);
|
||||
servlet.setProxyPath(proxyPath);
|
||||
servlet.setFileSystemWatched(fileSystemWatched);
|
||||
servlet.setCompileOnStartup(compileOnStartup);
|
||||
servlet.setLogBuildErrors(logBuildErrors);
|
||||
servlet.getProperties().putAll(properties);
|
||||
servlet.getPreservedClasses().addAll(preservedClasses);
|
||||
for (DevServerListener listener : listeners) {
|
||||
servlet.addListener(listener);
|
||||
}
|
||||
|
@ -147,12 +179,15 @@ public class DevServer {
|
|||
|
||||
try {
|
||||
server.start();
|
||||
server.join();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void awaitServer() throws InterruptedException {
|
||||
server.join();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
try {
|
||||
server.stop();
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function (window) {
|
||||
var boot = BOOT_FLAG;
|
||||
var reload = RELOAD_FLAG;
|
||||
var indicatorVisible = INDICATOR_FLAG;
|
||||
var debugPort = DEBUG_PORT;
|
||||
var deobfuscate = DEOBFUSCATE_FLAG;
|
||||
var fileName = FILE_NAME;
|
||||
var pathToFile = PATH_TO_FILE;
|
||||
(function () {
|
||||
let boot = BOOT_FLAG;
|
||||
let reload = RELOAD_FLAG;
|
||||
let indicatorVisible = INDICATOR_FLAG;
|
||||
let debugPort = DEBUG_PORT;
|
||||
let deobfuscate = DEOBFUSCATE_FLAG;
|
||||
let fileName = FILE_NAME;
|
||||
let pathToFile = PATH_TO_FILE;
|
||||
|
||||
function createWebSocket() {
|
||||
return new WebSocket("ws://WS_PATH");
|
||||
|
@ -28,18 +28,18 @@
|
|||
|
||||
function createIndicator() {
|
||||
function createMainElement() {
|
||||
var element = document.createElement("div");
|
||||
let element = document.createElement("div");
|
||||
element.style.position = "fixed";
|
||||
element.style.left = "0";
|
||||
element.style.bottom = "0";
|
||||
element.style.backgroundColor = "black";
|
||||
element.style.color = "white";
|
||||
element.style.opacity = 0.4;
|
||||
element.style.opacity = "0.4";
|
||||
element.style.padding = "5px";
|
||||
element.style.fontSize = "18px";
|
||||
element.style.fontWeight = "bold";
|
||||
element.style.pointerEvents = "none";
|
||||
element.style.zIndex = 1000;
|
||||
element.style.zIndex = "1000";
|
||||
element.style.display = "none";
|
||||
return element;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@
|
|||
}
|
||||
|
||||
function createProgressElements() {
|
||||
var element = document.createElement("span");
|
||||
const element = document.createElement("span");
|
||||
element.style.display = "none";
|
||||
element.style.marginLeft = "10px";
|
||||
element.style.width = "150px";
|
||||
|
@ -61,7 +61,7 @@
|
|||
element.style.backgroundColor = "white";
|
||||
element.style.position = "relative";
|
||||
|
||||
var progress = document.createElement("span");
|
||||
const progress = document.createElement("span");
|
||||
progress.style.display = "block";
|
||||
progress.style.position = "absolute";
|
||||
progress.style.left = "0";
|
||||
|
@ -80,9 +80,9 @@
|
|||
};
|
||||
}
|
||||
|
||||
var container = createMainElement();
|
||||
var label = createLabelElement();
|
||||
var progress = createProgressElements();
|
||||
const container = createMainElement();
|
||||
const label = createLabelElement();
|
||||
const progress = createProgressElements();
|
||||
container.appendChild(label);
|
||||
container.appendChild(progress.container);
|
||||
|
||||
|
@ -92,7 +92,7 @@
|
|||
progress: progress,
|
||||
timer: void 0,
|
||||
|
||||
show: function(text, timeout) {
|
||||
show(text, timeout) {
|
||||
this.container.style.display = "block";
|
||||
this.label.innerText = text;
|
||||
if (this.timer) {
|
||||
|
@ -118,7 +118,7 @@
|
|||
};
|
||||
}
|
||||
|
||||
var indicator = createIndicator();
|
||||
let indicator = createIndicator();
|
||||
function onLoad() {
|
||||
document.body.appendChild(indicator.container);
|
||||
}
|
||||
|
@ -137,15 +137,15 @@
|
|||
}
|
||||
|
||||
if (typeof main === 'function') {
|
||||
var oldMain = main;
|
||||
let oldMain = main;
|
||||
main = function() {
|
||||
var args = arguments;
|
||||
window.$teavm_deobfuscator_callback = function() {
|
||||
const args = arguments;
|
||||
window.$teavm_deobfuscator_callback = () => {
|
||||
oldMain.apply(window, args);
|
||||
};
|
||||
var elem = document.createElement("script");
|
||||
const elem = document.createElement("script");
|
||||
elem.src = pathToFile + fileName + ".deobfuscator.js";
|
||||
elem.onload = function() {
|
||||
elem.onload = () => {
|
||||
$teavm_deobfuscator([pathToFile + fileName + ".teavmdbg", pathToFile + fileName]);
|
||||
};
|
||||
document.head.append(elem);
|
||||
|
@ -165,9 +165,9 @@
|
|||
main();
|
||||
}
|
||||
|
||||
var ws = createWebSocket();
|
||||
let ws = createWebSocket();
|
||||
ws.onmessage = function(event) {
|
||||
var message = JSON.parse(event.data);
|
||||
const message = JSON.parse(event.data);
|
||||
switch (message.command) {
|
||||
case "compiling":
|
||||
indicator.show("Compiling...");
|
||||
|
@ -177,9 +177,9 @@
|
|||
if (message.success) {
|
||||
indicator.show("Compilation complete", 10);
|
||||
if (reload) {
|
||||
window.location.reload(true);
|
||||
window.location.reload();
|
||||
} else if (boot) {
|
||||
var scriptElem = document.createElement("script");
|
||||
const scriptElem = document.createElement("script");
|
||||
scriptElem.src = pathToFile + fileName;
|
||||
scriptElem.onload = startMain;
|
||||
document.head.appendChild(scriptElem);
|
||||
|
@ -197,12 +197,12 @@
|
|||
}
|
||||
|
||||
if (debugPort > 0) {
|
||||
var connected = false;
|
||||
let connected = false;
|
||||
function connectDebugAgent(event) {
|
||||
if (event.source !== window) {
|
||||
return;
|
||||
}
|
||||
var data = event.data;
|
||||
const data = event.data;
|
||||
if (typeof data.teavmDebuggerRequest !== "undefined" && !connected) {
|
||||
connected = true;
|
||||
window.postMessage({teavmDebugger: {port: debugPort}}, "*");
|
||||
|
@ -211,4 +211,4 @@
|
|||
window.addEventListener("message", connectDebugAgent);
|
||||
window.postMessage({teavmDebugger: {port: debugPort}}, "*");
|
||||
}
|
||||
})(this);
|
||||
})();
|
|
@ -74,6 +74,7 @@ val createConfig by tasks.registering {
|
|||
val jsoImpl = findArtifactCoordinates(":jso:impl")
|
||||
val metaprogrammingImpl = findArtifactCoordinates(":metaprogramming:impl")
|
||||
val tools = findArtifactCoordinates(":tools:core")
|
||||
val cli = findArtifactCoordinates(":tools:cli")
|
||||
val junit = findArtifactCoordinates(":tools:junit")
|
||||
doLast {
|
||||
val file = File(baseDir, "org/teavm/gradle/config/ArtifactCoordinates.java")
|
||||
|
@ -93,6 +94,7 @@ val createConfig by tasks.registering {
|
|||
public static final String JUNIT = "$junit";
|
||||
|
||||
public static final String TOOLS = "$tools";
|
||||
public static final String CLI = "$cli";
|
||||
|
||||
private ArtifactCoordinates() {
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.gradle;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import javax.inject.Inject;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
|
@ -24,6 +25,7 @@ import org.teavm.gradle.api.OptimizationLevel;
|
|||
import org.teavm.gradle.api.SourceFilePolicy;
|
||||
import org.teavm.gradle.api.TeaVMCConfiguration;
|
||||
import org.teavm.gradle.api.TeaVMCommonConfiguration;
|
||||
import org.teavm.gradle.api.TeaVMDevServerConfiguration;
|
||||
import org.teavm.gradle.api.TeaVMExtension;
|
||||
import org.teavm.gradle.api.TeaVMJSConfiguration;
|
||||
import org.teavm.gradle.api.TeaVMWasiConfiguration;
|
||||
|
@ -38,7 +40,7 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio
|
|||
|
||||
TeaVMExtensionImpl(Project project, ObjectFactory objectFactory) {
|
||||
super(project, objectFactory);
|
||||
js = objectFactory.newInstance(TeaVMJSConfiguration.class);
|
||||
js = objectFactory.newInstance(JsConfigImpl.class);
|
||||
wasm = objectFactory.newInstance(TeaVMWasmConfiguration.class);
|
||||
wasi = objectFactory.newInstance(TeaVMWasiConfiguration.class);
|
||||
c = objectFactory.newInstance(TeaVMCConfiguration.class);
|
||||
|
@ -72,6 +74,14 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio
|
|||
js.getSourceFilePolicy().convention(property("js.sourceFilePolicy")
|
||||
.map(SourceFilePolicy::valueOf)
|
||||
.orElse(SourceFilePolicy.DO_NOTHING));
|
||||
js.getDevServer().getStackDeobfuscated().convention(property("js.devServer.stackDeobfuscated")
|
||||
.map(Boolean::parseBoolean));
|
||||
js.getDevServer().getIndicator().convention(property("js.devServer.indicator").map(Boolean::parseBoolean));
|
||||
js.getDevServer().getAutoReload().convention(property("js.devServer.autoReload").map(Boolean::parseBoolean));
|
||||
js.getDevServer().getPort().convention(property("js.devServer.port").map(Integer::parseInt));
|
||||
js.getDevServer().getProxyUrl().convention(property("js.devServer.proxy.url"));
|
||||
js.getDevServer().getProxyPath().convention(property("js.devServer.proxy.path"));
|
||||
js.getDevServer().getProcessMemory().convention(property("js.devServer.memory").map(Integer::parseInt));
|
||||
}
|
||||
|
||||
private void setupWasmDefaults() {
|
||||
|
@ -199,4 +209,28 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio
|
|||
target.getOutOfProcess().convention(source.getOutOfProcess());
|
||||
target.getProcessMemory().convention(source.getProcessMemory());
|
||||
}
|
||||
|
||||
static abstract class JsConfigImpl implements TeaVMJSConfiguration {
|
||||
private TeaVMDevServerConfiguration devServer;
|
||||
|
||||
@Inject
|
||||
public JsConfigImpl(Project project) {
|
||||
devServer = project.getObjects().newInstance(TeaVMDevServerConfiguration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void devServer(Action<TeaVMDevServerConfiguration> action) {
|
||||
action.execute(devServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMDevServerConfiguration getDevServer() {
|
||||
return devServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void devServer(Closure<?> action) {
|
||||
action.rehydrate(getDevServer(), action.getOwner(), action.getThisObject()).call();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.gradle.api.artifacts.Configuration;
|
|||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
|
||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
|
||||
import org.gradle.api.artifacts.result.ResolvedDependencyResult;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.DuplicatesStrategy;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
|
@ -40,17 +41,22 @@ import org.teavm.gradle.tasks.GenerateCTask;
|
|||
import org.teavm.gradle.tasks.GenerateJavaScriptTask;
|
||||
import org.teavm.gradle.tasks.GenerateWasiTask;
|
||||
import org.teavm.gradle.tasks.GenerateWasmTask;
|
||||
import org.teavm.gradle.tasks.JavaScriptDevServerTask;
|
||||
import org.teavm.gradle.tasks.StopJavaScriptDevServerTask;
|
||||
import org.teavm.gradle.tasks.TeaVMTask;
|
||||
|
||||
public class TeaVMPlugin implements Plugin<Project> {
|
||||
public static final String EXTENSION_NAME = "teavm";
|
||||
public static final String SOURCE_SET_NAME = "teavm";
|
||||
public static final String JS_TASK_NAME = "generateJavaScript";
|
||||
public static final String JS_DEV_SERVER_TASK_NAME = "javaScriptDevServer";
|
||||
public static final String STOP_JS_DEV_SERVER_TASK_NAME = "stopJavaScriptDevServer";
|
||||
public static final String WASM_TASK_NAME = "generateWasm";
|
||||
public static final String WASI_TASK_NAME = "generateWasi";
|
||||
public static final String C_TASK_NAME = "generateC";
|
||||
public static final String CONFIGURATION_NAME = "teavm";
|
||||
public static final String CLASSPATH_CONFIGURATION_NAME = "teavmClasspath";
|
||||
public static final String TASK_GROUP = "TeaVM";
|
||||
private ObjectFactory objectFactory;
|
||||
|
||||
@Inject
|
||||
|
@ -105,7 +111,11 @@ public class TeaVMPlugin implements Plugin<Project> {
|
|||
private void registerTasks(Project project) {
|
||||
var compilerConfig = project.getConfigurations().detachedConfiguration(
|
||||
project.getDependencies().create(ArtifactCoordinates.TOOLS));
|
||||
var cliConfig = project.getConfigurations().detachedConfiguration(
|
||||
project.getDependencies().create(ArtifactCoordinates.CLI));
|
||||
registerJsTask(project, compilerConfig);
|
||||
registerJsDevServerTask(project, cliConfig);
|
||||
registerStopJsDevServerTask(project);
|
||||
registerWasmTask(project, compilerConfig);
|
||||
registerWasiTask(project, compilerConfig);
|
||||
registerCTask(project, compilerConfig);
|
||||
|
@ -125,47 +135,44 @@ public class TeaVMPlugin implements Plugin<Project> {
|
|||
task.getSourceFilePolicy().convention(js.getSourceFilePolicy());
|
||||
task.getMaxTopLevelNames().convention(js.getMaxTopLevelNames());
|
||||
|
||||
task.getSourceFiles().from(project.provider(() -> {
|
||||
var result = new ArrayList<File>();
|
||||
addSourceDirs(project, result);
|
||||
return result;
|
||||
}));
|
||||
task.getSourceFiles().from(project.provider(() -> {
|
||||
var dependencies = project.getConfigurations()
|
||||
.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)
|
||||
.getIncoming()
|
||||
.getResolutionResult()
|
||||
.getAllDependencies();
|
||||
setupSources(task.getSourceFiles(), project);
|
||||
});
|
||||
}
|
||||
|
||||
var result = new ArrayList<File>();
|
||||
for (var dependencyResult : dependencies) {
|
||||
if (!(dependencyResult instanceof ResolvedDependencyResult)) {
|
||||
continue;
|
||||
private void registerJsDevServerTask(Project project, Configuration configuration) {
|
||||
var extension = project.getExtensions().getByType(TeaVMExtension.class);
|
||||
project.getTasks().create(JS_DEV_SERVER_TASK_NAME, JavaScriptDevServerTask.class, task -> {
|
||||
var js = extension.getJs();
|
||||
task.setGroup(TASK_GROUP);
|
||||
task.getMainClass().convention(js.getMainClass());
|
||||
task.getClasspath().from(task.getProject().getConfigurations().getByName(CLASSPATH_CONFIGURATION_NAME));
|
||||
task.getPreservedClasses().addAll(js.getPreservedClasses());
|
||||
task.getProcessMemory().convention(js.getDevServer().getProcessMemory());
|
||||
task.getProperties().putAll(js.getProperties());
|
||||
task.getServerClasspath().from(configuration);
|
||||
task.getTargetFilePath().convention(js.getRelativePathInOutputDir());
|
||||
task.getTargetFileName().convention(js.getTargetFileName());
|
||||
task.getStackDeobfuscated().convention(js.getDevServer().getStackDeobfuscated());
|
||||
task.getIndicator().convention(js.getDevServer().getIndicator());
|
||||
task.getAutoReload().convention(js.getDevServer().getAutoReload());
|
||||
task.getPort().convention(js.getDevServer().getPort());
|
||||
task.getProxyUrl().convention(js.getDevServer().getProxyUrl());
|
||||
task.getProxyPath().convention(js.getDevServer().getProxyPath());
|
||||
task.getProcessMemory().convention(js.getDevServer().getProcessMemory());
|
||||
|
||||
var sourceSets = project.getExtensions().findByType(SourceSetContainer.class);
|
||||
if (sourceSets != null) {
|
||||
task.getClasspath().from(sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput());
|
||||
task.getClasspath().from(sourceSets.getByName(SOURCE_SET_NAME).getOutput());
|
||||
}
|
||||
var id = ((ResolvedDependencyResult) dependencyResult).getSelected().getId();
|
||||
if (id instanceof ProjectComponentIdentifier) {
|
||||
var path = ((ProjectComponentIdentifier) id).getProjectPath();
|
||||
var refProject = project.getRootProject().findProject(path);
|
||||
if (refProject != null) {
|
||||
addSourceDirs(refProject, result);
|
||||
|
||||
setupSources(task.getSourceFiles(), project);
|
||||
});
|
||||
}
|
||||
} else if (id instanceof ModuleComponentIdentifier) {
|
||||
var moduleId = (ModuleComponentIdentifier) id;
|
||||
var sourcesDep = project.getDependencies().create(Map.of(
|
||||
"group", moduleId.getGroup(),
|
||||
"name", moduleId.getModuleIdentifier().getName(),
|
||||
"version", moduleId.getVersion(),
|
||||
"classifier", "sources"
|
||||
));
|
||||
var tmpConfig = project.getConfigurations().detachedConfiguration(sourcesDep);
|
||||
tmpConfig.setTransitive(false);
|
||||
if (!tmpConfig.getResolvedConfiguration().hasError()) {
|
||||
result.addAll(tmpConfig.getResolvedConfiguration().getLenientConfiguration().getFiles());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
|
||||
private void registerStopJsDevServerTask(Project project) {
|
||||
project.getTasks().create(STOP_JS_DEV_SERVER_TASK_NAME, StopJavaScriptDevServerTask.class, task -> {
|
||||
task.setGroup(TASK_GROUP);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -270,5 +277,51 @@ public class TeaVMPlugin implements Plugin<Project> {
|
|||
task.getClasspath().from(sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput());
|
||||
task.getClasspath().from(sourceSets.getByName(SOURCE_SET_NAME).getOutput());
|
||||
}
|
||||
|
||||
task.setGroup(TASK_GROUP);
|
||||
}
|
||||
|
||||
private void setupSources(ConfigurableFileCollection sources, Project project) {
|
||||
sources.from(project.provider(() -> {
|
||||
var result = new ArrayList<File>();
|
||||
addSourceDirs(project, result);
|
||||
return result;
|
||||
}));
|
||||
sources.from(project.provider(() -> {
|
||||
var dependencies = project.getConfigurations()
|
||||
.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)
|
||||
.getIncoming()
|
||||
.getResolutionResult()
|
||||
.getAllDependencies();
|
||||
|
||||
var result = new ArrayList<File>();
|
||||
for (var dependencyResult : dependencies) {
|
||||
if (!(dependencyResult instanceof ResolvedDependencyResult)) {
|
||||
continue;
|
||||
}
|
||||
var id = ((ResolvedDependencyResult) dependencyResult).getSelected().getId();
|
||||
if (id instanceof ProjectComponentIdentifier) {
|
||||
var path = ((ProjectComponentIdentifier) id).getProjectPath();
|
||||
var refProject = project.getRootProject().findProject(path);
|
||||
if (refProject != null) {
|
||||
addSourceDirs(refProject, result);
|
||||
}
|
||||
} else if (id instanceof ModuleComponentIdentifier) {
|
||||
var moduleId = (ModuleComponentIdentifier) id;
|
||||
var sourcesDep = project.getDependencies().create(Map.of(
|
||||
"group", moduleId.getGroup(),
|
||||
"name", moduleId.getModuleIdentifier().getName(),
|
||||
"version", moduleId.getVersion(),
|
||||
"classifier", "sources"
|
||||
));
|
||||
var tmpConfig = project.getConfigurations().detachedConfiguration(sourcesDep);
|
||||
tmpConfig.setTransitive(false);
|
||||
if (!tmpConfig.getResolvedConfiguration().hasError()) {
|
||||
result.addAll(tmpConfig.getResolvedConfiguration().getLenientConfiguration().getFiles());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2024 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.gradle.api;
|
||||
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
public interface TeaVMDevServerConfiguration {
|
||||
Property<Boolean> getStackDeobfuscated();
|
||||
|
||||
Property<Boolean> getIndicator();
|
||||
|
||||
Property<Boolean> getAutoReload();
|
||||
|
||||
Property<Integer> getPort();
|
||||
|
||||
Property<String> getProxyUrl();
|
||||
|
||||
Property<String> getProxyPath();
|
||||
|
||||
Property<Integer> getProcessMemory();
|
||||
}
|
|
@ -15,6 +15,9 @@
|
|||
*/
|
||||
package org.teavm.gradle.api;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.DelegatesTo;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
public interface TeaVMJSConfiguration extends TeaVMWebConfiguration {
|
||||
|
@ -33,4 +36,10 @@ public interface TeaVMJSConfiguration extends TeaVMWebConfiguration {
|
|||
Property<SourceFilePolicy> getSourceFilePolicy();
|
||||
|
||||
Property<Integer> getMaxTopLevelNames();
|
||||
|
||||
TeaVMDevServerConfiguration getDevServer();
|
||||
|
||||
void devServer(Action<TeaVMDevServerConfiguration> action);
|
||||
|
||||
void devServer(@DelegatesTo(TeaVMDevServerConfiguration.class) Closure<?> action);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2024 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.gradle.tasks;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.invocation.Gradle;
|
||||
|
||||
public final class DevServerManager {
|
||||
private static DevServerManager instance;
|
||||
private final ConcurrentMap<String, ProjectDevServerManager> projectManagers = new ConcurrentHashMap<>();
|
||||
|
||||
private DevServerManager() {
|
||||
}
|
||||
|
||||
public ProjectDevServerManager getProjectManager(String path) {
|
||||
return projectManagers.computeIfAbsent(path, this::createProjectManager);
|
||||
}
|
||||
|
||||
private ProjectDevServerManager createProjectManager(String path) {
|
||||
return new ProjectDevServerManager();
|
||||
}
|
||||
|
||||
public void cleanup(Gradle gradle) {
|
||||
var allProjectPaths = new HashSet<String>();
|
||||
collectProjects(gradle.getRootProject(), allProjectPaths);
|
||||
var keysToRemove = new HashSet<>(projectManagers.keySet());
|
||||
keysToRemove.removeAll(allProjectPaths);
|
||||
for (var path : keysToRemove) {
|
||||
var pm = projectManagers.remove(path);
|
||||
if (pm != null) {
|
||||
pm.stop(gradle.getRootProject().getLogger());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static DevServerManager instance() {
|
||||
if (instance == null) {
|
||||
instance = new DevServerManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static void collectProjects(Project project, Set<String> collector) {
|
||||
if (!collector.add(project.getPath())) {
|
||||
return;
|
||||
}
|
||||
for (var child : project.getChildProjects().values()) {
|
||||
collectProjects(child, collector);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright 2024 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.gradle.tasks;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.inject.Inject;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Classpath;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.internal.logging.progress.ProgressLoggerFactory;
|
||||
|
||||
public abstract class JavaScriptDevServerTask extends DefaultTask {
|
||||
@Classpath
|
||||
public abstract ConfigurableFileCollection getClasspath();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<String> getTargetFileName();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<String> getTargetFilePath();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract MapProperty<String, String> getProperties();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract ListProperty<String> getPreservedClasses();
|
||||
|
||||
@Input
|
||||
public abstract Property<String> getMainClass();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<Boolean> getStackDeobfuscated();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<Boolean> getIndicator();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<Integer> getPort();
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getSourceFiles();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<Boolean> getAutoReload();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<String> getProxyUrl();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<String> getProxyPath();
|
||||
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<Integer> getProcessMemory();
|
||||
|
||||
@Classpath
|
||||
public abstract ConfigurableFileCollection getServerClasspath();
|
||||
|
||||
@Internal
|
||||
public abstract Property<Integer> getServerDebugPort();
|
||||
|
||||
@Inject
|
||||
protected abstract ProgressLoggerFactory getProgressLoggerFactory();
|
||||
|
||||
@TaskAction
|
||||
public void compileInCodeServer() throws IOException {
|
||||
var codeServerManager = DevServerManager.instance();
|
||||
codeServerManager.cleanup(getProject().getGradle());
|
||||
var pm = codeServerManager.getProjectManager(getProject().getPath());
|
||||
|
||||
pm.setClasspath(getClasspath().getFiles());
|
||||
pm.setSources(getSourceFiles().getFiles());
|
||||
if (getTargetFileName().isPresent()) {
|
||||
pm.setTargetFileName(getTargetFileName().get());
|
||||
}
|
||||
|
||||
if (getTargetFilePath().isPresent()) {
|
||||
pm.setTargetFilePath(getTargetFilePath().get());
|
||||
}
|
||||
|
||||
pm.setProperties(getProperties().get());
|
||||
pm.setPreservedClasses(getPreservedClasses().get());
|
||||
|
||||
pm.setServerClasspath(getServerClasspath().getFiles());
|
||||
pm.setMainClass(getMainClass().get());
|
||||
|
||||
pm.setStackDeobfuscated(!getStackDeobfuscated().isPresent() || getStackDeobfuscated().get());
|
||||
pm.setIndicator(getIndicator().isPresent() && getIndicator().get());
|
||||
pm.setAutoReload(getAutoReload().isPresent() && getAutoReload().get());
|
||||
|
||||
if (getPort().isPresent()) {
|
||||
pm.setPort(getPort().get());
|
||||
}
|
||||
if (getProxyUrl().isPresent()) {
|
||||
pm.setProxyUrl(getProxyUrl().get());
|
||||
}
|
||||
if (getProxyPath().isPresent()) {
|
||||
pm.setProxyPath(getProxyPath().get());
|
||||
}
|
||||
|
||||
if (getProcessMemory().isPresent()) {
|
||||
pm.setProcessMemory(getProcessMemory().get());
|
||||
}
|
||||
if (getServerDebugPort().isPresent()) {
|
||||
pm.setDebugPort(getServerDebugPort().get());
|
||||
}
|
||||
|
||||
var progress = getProgressLoggerFactory().newOperation(getClass());
|
||||
progress.start("Compilation", getName());
|
||||
pm.runBuild(getLogger(), progress);
|
||||
progress.completed();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,589 @@
|
|||
/*
|
||||
* Copyright 2024 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.gradle.tasks;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.stream.Collectors;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.internal.logging.progress.ProgressLogger;
|
||||
import org.teavm.common.json.JsonArrayValue;
|
||||
import org.teavm.common.json.JsonObjectValue;
|
||||
import org.teavm.common.json.JsonParser;
|
||||
import org.teavm.common.json.JsonValue;
|
||||
|
||||
public class ProjectDevServerManager {
|
||||
private Set<File> serverClasspath = new LinkedHashSet<>();
|
||||
private Set<File> classpath = new LinkedHashSet<>();
|
||||
private String targetFileName;
|
||||
private String targetFilePath;
|
||||
private Map<String, String> properties = new LinkedHashMap<>();
|
||||
private Set<String> preservedClasses = new LinkedHashSet<>();
|
||||
private String mainClass;
|
||||
private boolean stackDeobfuscated;
|
||||
private boolean indicator;
|
||||
private int port;
|
||||
private Set<File> sources = new HashSet<>();
|
||||
private boolean autoReload;
|
||||
private String proxyUrl;
|
||||
private String proxyPath;
|
||||
private int processMemory;
|
||||
private int debugPort;
|
||||
|
||||
private Process process;
|
||||
private Thread processKillHook;
|
||||
private Thread commandInputThread;
|
||||
private Thread stderrThread;
|
||||
private BufferedWriter commandOutput;
|
||||
private JsonParser jsonParser;
|
||||
private BlockingQueue<Runnable> eventQueue = new LinkedBlockingQueue<>();
|
||||
private boolean eventQueueDone;
|
||||
private Logger logger;
|
||||
private ProgressLogger progressLogger;
|
||||
|
||||
private Set<File> runningServerClasspath = new HashSet<>();
|
||||
private Set<File> runningClasspath = new HashSet<>();
|
||||
private String runningTargetFileName;
|
||||
private String runningTargetFilePath;
|
||||
private Map<String, String> runningProperties = new HashMap<>();
|
||||
private Set<String> runningPreservedClasses = new HashSet<>();
|
||||
private String runningMainClass;
|
||||
private boolean runningStackDeobfuscated;
|
||||
private boolean runningIndicator;
|
||||
private int runningPort;
|
||||
private Set<File> runningSources = new HashSet<>();
|
||||
private boolean runningAutoReload;
|
||||
private String runningProxyUrl;
|
||||
private String runningProxyPath;
|
||||
private int runningProcessMemory;
|
||||
private int runningDebugPort;
|
||||
|
||||
ProjectDevServerManager() {
|
||||
jsonParser = JsonParser.ofValue(this::parseCommand);
|
||||
}
|
||||
|
||||
public void setServerClasspath(Set<File> serverClasspath) {
|
||||
this.serverClasspath.clear();
|
||||
this.serverClasspath.addAll(serverClasspath);
|
||||
}
|
||||
|
||||
public void setClasspath(Set<File> classpath) {
|
||||
this.classpath.clear();
|
||||
this.classpath.addAll(classpath);
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, String> properties) {
|
||||
this.properties.clear();
|
||||
this.properties.putAll(properties);
|
||||
}
|
||||
|
||||
public void setPreservedClasses(Collection<String> preservedClasses) {
|
||||
this.preservedClasses.clear();
|
||||
this.preservedClasses.addAll(preservedClasses);
|
||||
}
|
||||
|
||||
public void setTargetFileName(String targetFileName) {
|
||||
this.targetFileName = targetFileName;
|
||||
}
|
||||
|
||||
public void setTargetFilePath(String targetFilePath) {
|
||||
this.targetFilePath = targetFilePath;
|
||||
}
|
||||
|
||||
public void setMainClass(String mainClass) {
|
||||
this.mainClass = mainClass;
|
||||
}
|
||||
|
||||
public void setStackDeobfuscated(boolean stackDeobfuscated) {
|
||||
this.stackDeobfuscated = stackDeobfuscated;
|
||||
}
|
||||
|
||||
public void setIndicator(boolean indicator) {
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public void setSources(Set<File> sources) {
|
||||
this.sources.clear();
|
||||
this.sources.addAll(sources);
|
||||
}
|
||||
|
||||
public void setAutoReload(boolean autoReload) {
|
||||
this.autoReload = autoReload;
|
||||
}
|
||||
|
||||
public void setProxyUrl(String proxyUrl) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
}
|
||||
|
||||
public void setProxyPath(String proxyPath) {
|
||||
this.proxyPath = proxyPath;
|
||||
}
|
||||
|
||||
public void setProcessMemory(int processMemory) {
|
||||
this.processMemory = processMemory;
|
||||
}
|
||||
|
||||
public void setDebugPort(int debugPort) {
|
||||
this.debugPort = debugPort;
|
||||
}
|
||||
|
||||
public void runBuild(Logger logger, ProgressLogger progressLogger) throws IOException {
|
||||
restartIfNecessary(logger);
|
||||
try {
|
||||
schedule(() -> {
|
||||
try {
|
||||
commandOutput.write("{\"type\":\"build\"}\n");
|
||||
commandOutput.flush();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
processQueue(logger, progressLogger);
|
||||
}
|
||||
|
||||
private void processQueue(Logger logger, ProgressLogger progressLogger) {
|
||||
eventQueueDone = false;
|
||||
this.logger = logger;
|
||||
this.progressLogger = progressLogger;
|
||||
var stoppedUnexpectedly = new boolean[1];
|
||||
var processMonitorThread = new Thread(() -> {
|
||||
try {
|
||||
process.waitFor();
|
||||
schedule(() -> {
|
||||
stoppedUnexpectedly[0] = true;
|
||||
});
|
||||
stopEventQueue();
|
||||
} catch (InterruptedException e) {
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
processMonitorThread.setDaemon(true);
|
||||
processMonitorThread.setName("Dev server process crash monitor");
|
||||
processMonitorThread.start();
|
||||
try {
|
||||
while (!eventQueueDone || !eventQueue.isEmpty()) {
|
||||
Runnable command;
|
||||
try {
|
||||
command = eventQueue.take();
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
command.run();
|
||||
}
|
||||
if (stoppedUnexpectedly[0]) {
|
||||
logger.error("Dev server process stopped unexpectedly");
|
||||
throw new GradleException();
|
||||
}
|
||||
} finally {
|
||||
this.logger = null;
|
||||
this.progressLogger = null;
|
||||
processMonitorThread.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private void restartIfNecessary(Logger logger) throws IOException {
|
||||
if (process != null && !checkProcess()) {
|
||||
logger.info("Changes detected in TeaVM development server config, restarting server");
|
||||
stop(logger);
|
||||
}
|
||||
if (process == null || !process.isAlive()) {
|
||||
start(logger);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(Logger logger) {
|
||||
if (process != null) {
|
||||
logger.info("Stopping TeaVM development server, PID = {}", process.pid());
|
||||
if (process.isAlive()) {
|
||||
try {
|
||||
commandOutput.write("{\"type\":\"stop\"}\n");
|
||||
commandOutput.flush();
|
||||
} catch (IOException e) {
|
||||
process.destroy();
|
||||
}
|
||||
try {
|
||||
process.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
// do nothing
|
||||
}
|
||||
} else {
|
||||
logger.info("Process was dead");
|
||||
}
|
||||
process = null;
|
||||
Runtime.getRuntime().removeShutdownHook(processKillHook);
|
||||
processKillHook = null;
|
||||
commandInputThread.interrupt();
|
||||
commandInputThread = null;
|
||||
stderrThread.interrupt();
|
||||
stderrThread = null;
|
||||
commandOutput = null;
|
||||
} else {
|
||||
logger.info("No development server running, doing nothing");
|
||||
}
|
||||
}
|
||||
|
||||
private void start(Logger logger) throws IOException {
|
||||
logger.info("Starting TeaVM development server");
|
||||
|
||||
var pb = new ProcessBuilder();
|
||||
pb.command(getBuilderCommand().toArray(new String[0]));
|
||||
|
||||
process = pb.start();
|
||||
processKillHook = new Thread(() -> process.destroy());
|
||||
Runtime.getRuntime().addShutdownHook(processKillHook);
|
||||
commandOutput = new BufferedWriter(new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8));
|
||||
|
||||
commandInputThread = new Thread(this::readCommandsFromProcess);
|
||||
commandInputThread.setName("TeaVM development server command reader");
|
||||
commandInputThread.setDaemon(true);
|
||||
commandInputThread.start();
|
||||
|
||||
stderrThread = new Thread(this::readStderrFromProcess);
|
||||
stderrThread.setName("TeaVM development server stderr reader");
|
||||
stderrThread.setDaemon(true);
|
||||
stderrThread.start();
|
||||
|
||||
logger.info("Development server started");
|
||||
}
|
||||
|
||||
private void readCommandsFromProcess() {
|
||||
try (var input = new BufferedReader(new InputStreamReader(process.getInputStream(),
|
||||
StandardCharsets.UTF_8))) {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
var command = input.readLine();
|
||||
if (command == null) {
|
||||
break;
|
||||
}
|
||||
schedule(() -> readCommand(command));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
stopEventQueue();
|
||||
if (logger != null) {
|
||||
logger.error("IO error occurred reading stdout of development server process", e);
|
||||
}
|
||||
} catch (InterruptedException e2) {
|
||||
if (logger != null) {
|
||||
logger.info("Development server process input thread interrupted");
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
if (logger != null) {
|
||||
logger.info("Development server process input thread interrupted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readStderrFromProcess() {
|
||||
try (var input = new BufferedReader(new InputStreamReader(process.getErrorStream(),
|
||||
StandardCharsets.UTF_8))) {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
var line = input.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
schedule(() -> logger.warn("server stderr: {}", line));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (logger != null) {
|
||||
logger.error("IO error occurred reading stderr of development server process", e);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
if (logger != null) {
|
||||
logger.info("Development server process input thread interrupted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopEventQueue() throws InterruptedException {
|
||||
schedule(() -> eventQueueDone = true);
|
||||
}
|
||||
|
||||
private void schedule(Runnable command) throws InterruptedException {
|
||||
eventQueue.put(command);
|
||||
}
|
||||
|
||||
private void readCommand(String command) {
|
||||
try {
|
||||
jsonParser.parse(new StringReader(command));
|
||||
} catch (IOException e) {
|
||||
// This should not happen
|
||||
throw new RuntimeException(e);
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeException("Error reading command: " + command, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseCommand(JsonValue command) {
|
||||
var obj = (JsonObjectValue) command;
|
||||
var type = obj.get("type").asString();
|
||||
try {
|
||||
switch (type) {
|
||||
case "log":
|
||||
logCommand(obj);
|
||||
break;
|
||||
case "compilation-started":
|
||||
// do nothing
|
||||
break;
|
||||
case "compilation-progress":
|
||||
progressCommand(obj);
|
||||
break;
|
||||
case "compilation-complete":
|
||||
completeCommand(obj);
|
||||
break;
|
||||
case "compilation-cancelled":
|
||||
stopEventQueue();
|
||||
break;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
private void logCommand(JsonObjectValue command) throws InterruptedException {
|
||||
if (logger == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var level = command.get("level").asString();
|
||||
var message = command.get("message").asString();
|
||||
var throwable = command.get("throwable");
|
||||
if (throwable != null) {
|
||||
message += "\n" + throwable.asString();
|
||||
}
|
||||
var messageToReport = message;
|
||||
switch (level) {
|
||||
case "debug":
|
||||
schedule(() -> logger.debug(messageToReport));
|
||||
break;
|
||||
case "info":
|
||||
schedule(() -> logger.info(messageToReport));
|
||||
break;
|
||||
case "warning":
|
||||
schedule(() -> logger.warn(messageToReport));
|
||||
break;
|
||||
case "error":
|
||||
schedule(() -> logger.error(messageToReport));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void progressCommand(JsonObjectValue command) throws InterruptedException {
|
||||
if (progressLogger == null) {
|
||||
return;
|
||||
}
|
||||
var progress = command.get("progress").asNumber();
|
||||
var roundedResult = (int) (progress * 1000 + 5) / 10;
|
||||
var result = Math.min(100, roundedResult / 10.0);
|
||||
schedule(() -> progressLogger.progress(result + " %"));
|
||||
}
|
||||
|
||||
private void completeCommand(JsonObjectValue command) throws InterruptedException {
|
||||
var problemsJson = command.get("problems");
|
||||
if (problemsJson != null && logger != null) {
|
||||
reportProblems((JsonArrayValue) problemsJson);
|
||||
}
|
||||
stopEventQueue();
|
||||
}
|
||||
|
||||
private void reportProblems(JsonArrayValue json) throws InterruptedException {
|
||||
var hasSevere = false;
|
||||
for (var i = 0; i < json.size(); ++i) {
|
||||
var problem = json.get(i).asObject();
|
||||
var severity = problem.get("severity").asString();
|
||||
var sb = new StringBuilder();
|
||||
sb.append(problem.get("message").asString());
|
||||
sb.append(problem.get("location").asString());
|
||||
var message = sb.toString();
|
||||
switch (severity) {
|
||||
case "error":
|
||||
hasSevere = true;
|
||||
schedule(() -> logger.error(message));
|
||||
break;
|
||||
case "warning":
|
||||
schedule(() -> logger.warn(message));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasSevere) {
|
||||
schedule(() -> {
|
||||
throw new GradleException("Errors occurred during TeaVM build");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getBuilderCommand() {
|
||||
var command = new ArrayList<String>();
|
||||
|
||||
var javaHome = System.getProperty("java.home");
|
||||
var javaExec = javaHome + "/bin/java";
|
||||
if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
|
||||
javaExec += ".exe";
|
||||
}
|
||||
command.add(javaExec);
|
||||
|
||||
if (!serverClasspath.isEmpty()) {
|
||||
command.add("-cp");
|
||||
command.add(serverClasspath.stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.joining(File.pathSeparator)));
|
||||
}
|
||||
runningServerClasspath.clear();
|
||||
runningServerClasspath.addAll(serverClasspath);
|
||||
|
||||
if (processMemory != 0) {
|
||||
command.add("-Xmx" + processMemory + "m");
|
||||
}
|
||||
runningProcessMemory = processMemory;
|
||||
|
||||
if (debugPort != 0) {
|
||||
command.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=*:" + debugPort);
|
||||
}
|
||||
runningDebugPort = debugPort;
|
||||
|
||||
command.add("org.teavm.cli.devserver.TeaVMDevServerRunner");
|
||||
command.add("--json-interface");
|
||||
command.add("--no-watch");
|
||||
|
||||
if (targetFileName != null) {
|
||||
command.add("--targetfile");
|
||||
command.add(targetFileName);
|
||||
}
|
||||
runningTargetFileName = targetFileName;
|
||||
|
||||
if (targetFilePath != null) {
|
||||
command.add("--targetdir");
|
||||
command.add(targetFilePath);
|
||||
}
|
||||
runningTargetFilePath = targetFilePath;
|
||||
|
||||
if (!classpath.isEmpty()) {
|
||||
command.add("--classpath");
|
||||
command.addAll(classpath.stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
runningClasspath.clear();
|
||||
runningClasspath.addAll(classpath);
|
||||
|
||||
if (!sources.isEmpty()) {
|
||||
command.add("--sourcepath");
|
||||
command.addAll(sources.stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
runningSources.clear();
|
||||
runningSources.addAll(sources);
|
||||
|
||||
if (port != 0) {
|
||||
command.add("--port");
|
||||
command.add(String.valueOf(port));
|
||||
}
|
||||
runningPort = port;
|
||||
|
||||
if (indicator) {
|
||||
command.add("--indicator");
|
||||
}
|
||||
runningIndicator = indicator;
|
||||
|
||||
if (stackDeobfuscated) {
|
||||
command.add("--deobfuscate-stack");
|
||||
}
|
||||
runningStackDeobfuscated = stackDeobfuscated;
|
||||
|
||||
if (autoReload) {
|
||||
command.add("--auto-reload");
|
||||
}
|
||||
runningAutoReload = autoReload;
|
||||
|
||||
if (proxyUrl != null) {
|
||||
command.add("--proxy-url");
|
||||
command.add(proxyUrl);
|
||||
}
|
||||
runningProxyUrl = proxyUrl;
|
||||
|
||||
if (proxyPath != null) {
|
||||
command.add("--proxy-path");
|
||||
command.add(proxyPath);
|
||||
}
|
||||
runningProxyPath = proxyPath;
|
||||
|
||||
for (var entry : properties.entrySet()) {
|
||||
command.add("--property");
|
||||
command.add(entry.getKey() + "=" + entry.getValue());
|
||||
}
|
||||
runningProperties.clear();
|
||||
runningProperties.putAll(properties);
|
||||
|
||||
if (!preservedClasses.isEmpty()) {
|
||||
command.add("--preserved-classes");
|
||||
command.addAll(preservedClasses);
|
||||
}
|
||||
runningPreservedClasses.clear();
|
||||
runningPreservedClasses.addAll(preservedClasses);
|
||||
|
||||
command.add("--");
|
||||
command.add(mainClass);
|
||||
runningMainClass = mainClass;
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private boolean checkProcess() {
|
||||
return Objects.equals(serverClasspath, runningServerClasspath)
|
||||
&& Objects.equals(classpath, runningClasspath)
|
||||
&& Objects.equals(targetFileName, runningTargetFileName)
|
||||
&& Objects.equals(targetFilePath, runningTargetFilePath)
|
||||
&& Objects.equals(properties, runningProperties)
|
||||
&& Objects.equals(preservedClasses, runningPreservedClasses)
|
||||
&& Objects.equals(mainClass, runningMainClass)
|
||||
&& stackDeobfuscated == runningStackDeobfuscated
|
||||
&& indicator == runningIndicator
|
||||
&& port == runningPort
|
||||
&& Objects.equals(sources, runningSources)
|
||||
&& autoReload == runningAutoReload
|
||||
&& Objects.equals(proxyUrl, runningProxyUrl)
|
||||
&& Objects.equals(proxyPath, runningProxyPath)
|
||||
&& processMemory == runningProcessMemory
|
||||
&& debugPort == runningDebugPort;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2024 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.gradle.tasks;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
public abstract class StopJavaScriptDevServerTask extends DefaultTask {
|
||||
@TaskAction
|
||||
public void stopServer() {
|
||||
var codeServerManager = DevServerManager.instance();
|
||||
codeServerManager.cleanup(getProject().getGradle());
|
||||
var pm = codeServerManager.getProjectManager(getProject().getPath());
|
||||
pm.stop(getLogger());
|
||||
}
|
||||
}
|
|
@ -52,7 +52,6 @@ import org.teavm.vm.TeaVMProgressListener;
|
|||
|
||||
public abstract class TeaVMTask extends DefaultTask {
|
||||
public TeaVMTask() {
|
||||
setGroup("TeaVM");
|
||||
getDebugInformation().convention(false);
|
||||
getTargetFileName().convention("bundle");
|
||||
getOptimization().convention(OptimizationLevel.BALANCED);
|
||||
|
|
|
@ -22,10 +22,10 @@ plugins {
|
|||
description = "All-in one JAR file that used by IDE plugins"
|
||||
|
||||
dependencies {
|
||||
implementation(project(path = ":tools:core"))
|
||||
implementation(project(path = ":tools:devserver"))
|
||||
implementation(project(path = ":classlib"))
|
||||
implementation(project(path = ":tools:chrome-rdp"))
|
||||
api(project(":tools:core"))
|
||||
api(project(":tools:devserver"))
|
||||
api(project(":classlib"))
|
||||
api(project(":tools:chrome-rdp"))
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
|
|
|
@ -32,7 +32,8 @@ intellij {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(path = ":tools:ide-deps", configuration = "shadow").setTransitive(false))
|
||||
compileOnly(project(":tools:ide-deps"))
|
||||
runtimeOnly(project(path = ":tools:ide-deps", configuration = "shadow").setTransitive(false))
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
|
|
@ -153,6 +153,7 @@ public class DevServerRunner extends UnicastRemoteObject implements DevServerMan
|
|||
DevServerRunner daemon = new DevServerRunner(server);
|
||||
System.out.println(PORT_MESSAGE_PREFIX + daemon.port);
|
||||
server.start();
|
||||
server.awaitServer();
|
||||
|
||||
try {
|
||||
daemon.registry.unbind(ID);
|
||||
|
@ -327,7 +328,9 @@ public class DevServerRunner extends UnicastRemoteObject implements DevServerMan
|
|||
@Override
|
||||
public void compilationComplete(BuildResult buildResult) {
|
||||
DevServerBuildResult result = new DevServerBuildResult();
|
||||
if (buildResult != null) {
|
||||
result.problems.addAll(buildResult.getProblems().getProblems());
|
||||
}
|
||||
for (DevServerManagerListener listener : getListeners()) {
|
||||
try {
|
||||
listener.compilationComplete(result);
|
||||
|
|
Loading…
Reference in New Issue
Block a user