mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add TeaVM build daemon to IDEA
This commit is contained in:
parent
56398f58f9
commit
1ae4a95128
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2017 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.jps.model;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.model.ex.JpsElementBase;
|
||||
|
||||
public class TeaVMJpsWorkspaceConfiguration extends JpsElementBase<TeaVMJpsWorkspaceConfiguration> {
|
||||
private boolean daemonEnabled;
|
||||
|
||||
public boolean isDaemonEnabled() {
|
||||
return daemonEnabled;
|
||||
}
|
||||
|
||||
public void setDaemonEnabled(boolean daemonEnabled) {
|
||||
this.daemonEnabled = daemonEnabled;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TeaVMJpsWorkspaceConfiguration createCopy() {
|
||||
TeaVMJpsWorkspaceConfiguration copy = new TeaVMJpsWorkspaceConfiguration();
|
||||
copy.applyChanges(this);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyChanges(@NotNull TeaVMJpsWorkspaceConfiguration configuration) {
|
||||
daemonEnabled = configuration.daemonEnabled;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2017 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.jps.remote;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import org.teavm.vm.TeaVMPhase;
|
||||
import org.teavm.vm.TeaVMProgressFeedback;
|
||||
|
||||
public interface TeaVMRemoteBuildCallback extends Remote {
|
||||
TeaVMProgressFeedback phaseStarted(TeaVMPhase phase, int count) throws RemoteException;
|
||||
|
||||
TeaVMProgressFeedback progressReached(int progress) throws RemoteException;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2017 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.jps.remote;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.tooling.TeaVMTargetType;
|
||||
|
||||
public class TeaVMRemoteBuildRequest implements Serializable {
|
||||
public final List<String> sourceDirectories = new ArrayList<>();
|
||||
public final List<String> sourceJarFiles = new ArrayList<>();
|
||||
public final List<String> classPath = new ArrayList<>();
|
||||
public TeaVMTargetType targetType;
|
||||
public String mainClass;
|
||||
public String targetDirectory;
|
||||
public boolean sourceMapsFileGenerated;
|
||||
public boolean debugInformationGenerated;
|
||||
public boolean sourceFilesCopied;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2017 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.jps.remote;
|
||||
|
||||
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;
|
||||
|
||||
public class TeaVMRemoteBuildResponse implements Serializable {
|
||||
public CallGraph callGraph;
|
||||
public boolean errorOccurred;
|
||||
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<>();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2017 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.jps.remote;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
public interface TeaVMRemoteBuildService extends Remote {
|
||||
String REMOTE_PORT = "teavm.daemon.remote-port";
|
||||
String ID = "TeaVM-Daemon";
|
||||
|
||||
TeaVMRemoteBuildResponse build(TeaVMRemoteBuildRequest request, TeaVMRemoteBuildCallback callback)
|
||||
throws RemoteException;
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright 2017 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.jps;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.diagnostics.Problem;
|
||||
import org.teavm.diagnostics.ProblemProvider;
|
||||
import org.teavm.idea.jps.model.TeaVMBuildResult;
|
||||
import org.teavm.idea.jps.model.TeaVMBuildStrategy;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildCallback;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildRequest;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildResponse;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildService;
|
||||
import org.teavm.tooling.TeaVMTargetType;
|
||||
import org.teavm.vm.TeaVMPhase;
|
||||
import org.teavm.vm.TeaVMProgressFeedback;
|
||||
|
||||
public class RemoteBuildStrategy implements TeaVMBuildStrategy {
|
||||
private final CompileContext context;
|
||||
private TeaVMRemoteBuildRequest request;
|
||||
private TeaVMRemoteBuildService buildService;
|
||||
|
||||
public RemoteBuildStrategy(CompileContext context, TeaVMRemoteBuildService buildService) {
|
||||
this.context = context;
|
||||
this.buildService = buildService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
request = new TeaVMRemoteBuildRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSourcesDirectory(String directory) {
|
||||
request.sourceDirectories.add(directory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSourcesJar(String jarFile) {
|
||||
request.sourceJarFiles.add(jarFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClassPathEntries(List<String> entries) {
|
||||
request.classPath.addAll(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetType(TeaVMTargetType targetType) {
|
||||
request.targetType = targetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMainClass(String mainClass) {
|
||||
request.mainClass = mainClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetDirectory(String targetDirectory) {
|
||||
request.targetDirectory = targetDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceMapsFileGenerated(boolean sourceMapsFileGenerated) {
|
||||
request.sourceMapsFileGenerated = sourceMapsFileGenerated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDebugInformationGenerated(boolean debugInformationGenerated) {
|
||||
request.debugInformationGenerated = debugInformationGenerated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceFilesCopied(boolean sourceFilesCopied) {
|
||||
request.sourceFilesCopied = sourceFilesCopied;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMBuildResult build() {
|
||||
TeaVMRemoteBuildResponse response;
|
||||
try {
|
||||
response = buildService.build(request, new CallbackImpl(context));
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new TeaVMBuildResult() {
|
||||
private ProblemProvider problems = new ProblemProvider() {
|
||||
@Override
|
||||
public List<Problem> getProblems() {
|
||||
return response.problems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Problem> getSevereProblems() {
|
||||
return response.severeProblems;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public CallGraph getCallGraph() {
|
||||
return response.callGraph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorOccurred() {
|
||||
return response.errorOccurred;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProblemProvider getProblems() {
|
||||
return problems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getUsedResources() {
|
||||
return response.usedResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getClasses() {
|
||||
return response.classes;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class CallbackImpl extends UnicastRemoteObject implements TeaVMRemoteBuildCallback {
|
||||
private CompileContext context;
|
||||
int expectedCount;
|
||||
TeaVMPhase currentPhase;
|
||||
|
||||
public CallbackImpl(CompileContext context) throws RemoteException {
|
||||
super();
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback phaseStarted(TeaVMPhase phase, int count) throws RemoteException {
|
||||
expectedCount = count;
|
||||
context.processMessage(new ProgressMessage(phaseName(phase), 0));
|
||||
currentPhase = phase;
|
||||
return context.getCancelStatus().isCanceled() ? TeaVMProgressFeedback.CANCEL
|
||||
: TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback progressReached(int progress) throws RemoteException {
|
||||
context.processMessage(new ProgressMessage(phaseName(currentPhase), (float) progress / expectedCount));
|
||||
return context.getCancelStatus().isCanceled() ? TeaVMProgressFeedback.CANCEL
|
||||
: TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
private static String phaseName(TeaVMPhase phase) {
|
||||
switch (phase) {
|
||||
case DEPENDENCY_CHECKING:
|
||||
return "Discovering classes to compile";
|
||||
case LINKING:
|
||||
return "Resolving method invocations";
|
||||
case DECOMPILATION:
|
||||
return "Compiling classes";
|
||||
case OPTIMIZATION:
|
||||
return "Optimizing code";
|
||||
case RENDERING:
|
||||
return "Building JS file";
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,10 +33,13 @@ import org.jetbrains.jps.incremental.ProjectBuildException;
|
|||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.teavm.idea.jps.model.TeaVMBuildStrategy;
|
||||
import org.teavm.idea.jps.remote.TeaVMBuilderAssistant;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildService;
|
||||
|
||||
public class TeaVMBuilder extends ModuleLevelBuilder {
|
||||
private static TeaVMBuilderAssistant assistant;
|
||||
private TeaVMBuilderAssistant assistant;
|
||||
private TeaVMRemoteBuildService buildService;
|
||||
|
||||
public TeaVMBuilder() {
|
||||
super(BuilderCategory.CLASS_POST_PROCESSOR);
|
||||
|
@ -50,6 +53,16 @@ public class TeaVMBuilder extends ModuleLevelBuilder {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
String daemonPortString = System.getProperty(TeaVMRemoteBuildService.REMOTE_PORT);
|
||||
if (daemonPortString != null) {
|
||||
try {
|
||||
Registry registry = LocateRegistry.getRegistry(Integer.parseInt(daemonPortString));
|
||||
buildService = (TeaVMRemoteBuildService) registry.lookup(TeaVMRemoteBuildService.ID);
|
||||
} catch (NumberFormatException | RemoteException | NotBoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,7 +76,10 @@ public class TeaVMBuilder extends ModuleLevelBuilder {
|
|||
|
||||
boolean doneSomething = false;
|
||||
|
||||
TeaVMBuild build = new TeaVMBuild(context, assistant, new InProcessBuildStrategy(context));
|
||||
TeaVMBuildStrategy buildStrategy = buildService != null
|
||||
? new RemoteBuildStrategy(context, buildService)
|
||||
: new InProcessBuildStrategy(context);
|
||||
TeaVMBuild build = new TeaVMBuild(context, assistant, buildStrategy);
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
doneSomething |= build.perform(module, chunk.representativeTarget());
|
||||
if (context.getCancelStatus().isCanceled()) {
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2017 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;
|
||||
|
||||
import com.intellij.openapi.components.ApplicationComponent;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import java.io.IOException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.teavm.idea.daemon.TeaVMBuildDaemon;
|
||||
import org.teavm.idea.daemon.TeaVMDaemonInfo;
|
||||
import org.teavm.idea.jps.model.TeaVMJpsWorkspaceConfiguration;
|
||||
|
||||
public class TeaVMDaemonComponent implements ApplicationComponent {
|
||||
private TeaVMDaemonInfo daemonInfo;
|
||||
|
||||
@Override
|
||||
public void initComponent() {
|
||||
TeaVMWorkspaceConfigurationStorage configurationStorage = ServiceManager.getService(
|
||||
TeaVMWorkspaceConfigurationStorage.class);
|
||||
if (configurationStorage != null) {
|
||||
TeaVMJpsWorkspaceConfiguration configuration = configurationStorage.getState();
|
||||
if (configuration.isDaemonEnabled()) {
|
||||
startDaemon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TeaVMWorkspaceConfigurationStorage getConfigurationStorage() {
|
||||
return ServiceManager.getService(TeaVMWorkspaceConfigurationStorage.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeComponent() {
|
||||
if (daemonInfo != null) {
|
||||
daemonInfo.getProcess().destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDaemonRunning() {
|
||||
return daemonInfo != null;
|
||||
}
|
||||
|
||||
public int getDaemonPort() {
|
||||
return daemonInfo.getPort();
|
||||
}
|
||||
|
||||
public void startDaemon() {
|
||||
if (daemonInfo == null) {
|
||||
try {
|
||||
daemonInfo = TeaVMBuildDaemon.start();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
updateConfiguration(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopDaemon() {
|
||||
if (daemonInfo != null) {
|
||||
daemonInfo.getProcess().destroy();
|
||||
daemonInfo = null;
|
||||
updateConfiguration(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateConfiguration(boolean daemonEnabled) {
|
||||
TeaVMWorkspaceConfigurationStorage configurationStorage = getConfigurationStorage();
|
||||
TeaVMJpsWorkspaceConfiguration configuration = configurationStorage.getState();
|
||||
configuration.setDaemonEnabled(daemonEnabled);
|
||||
configurationStorage.loadState(configuration);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getComponentName() {
|
||||
return "TeaVM daemon";
|
||||
}
|
||||
}
|
|
@ -17,20 +17,28 @@ package org.teavm.idea;
|
|||
|
||||
import static org.teavm.idea.jps.remote.TeaVMBuilderAssistant.REMOTE_PORT;
|
||||
import com.intellij.compiler.server.BuildProcessParametersProvider;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildService;
|
||||
|
||||
public class TeaVMJPSConfigurator extends BuildProcessParametersProvider {
|
||||
private TeaVMJPSRemoteService remoteService;
|
||||
private TeaVMDaemonComponent daemonComponent;
|
||||
|
||||
public TeaVMJPSConfigurator(TeaVMJPSRemoteService remoteService) {
|
||||
public TeaVMJPSConfigurator(TeaVMJPSRemoteService remoteService, TeaVMDaemonComponent daemonComponent) {
|
||||
this.remoteService = remoteService;
|
||||
this.daemonComponent = daemonComponent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getVMArguments() {
|
||||
return Collections.singletonList("-D" + REMOTE_PORT + "=" + remoteService.getPort());
|
||||
List<String> result = new ArrayList<>();
|
||||
result.add("-D" + REMOTE_PORT + "=" + remoteService.getPort());
|
||||
if (daemonComponent.isDaemonRunning()) {
|
||||
result.add("-D" + TeaVMRemoteBuildService.REMOTE_PORT + "=" + daemonComponent.getDaemonPort());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
* Copyright 2017 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -19,20 +19,20 @@ import com.intellij.openapi.components.PersistentStateComponent;
|
|||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
|
||||
import org.teavm.idea.jps.model.TeaVMJpsWorkspaceConfiguration;
|
||||
|
||||
@State(name = "teavm", storages = @Storage(value = "$MODULE_FILE$"))
|
||||
public class TeaVMConfigurationStorage implements PersistentStateComponent<TeaVMJpsConfiguration> {
|
||||
private TeaVMJpsConfiguration state = new TeaVMJpsConfiguration();
|
||||
@State(name = "teavm", storages = @Storage(value = "teavm.xml"))
|
||||
public class TeaVMWorkspaceConfigurationStorage implements PersistentStateComponent<TeaVMJpsWorkspaceConfiguration> {
|
||||
private TeaVMJpsWorkspaceConfiguration state = new TeaVMJpsWorkspaceConfiguration();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TeaVMJpsConfiguration getState() {
|
||||
public TeaVMJpsWorkspaceConfiguration getState() {
|
||||
return state.createCopy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(TeaVMJpsConfiguration state) {
|
||||
this.state.applyChanges(state);
|
||||
public void loadState(TeaVMJpsWorkspaceConfiguration configuration) {
|
||||
state.applyChanges(configuration);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* Copyright 2017 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.daemon;
|
||||
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.ide.plugins.PluginManager;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.rmi.AlreadyBoundException;
|
||||
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.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildCallback;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildRequest;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildResponse;
|
||||
import org.teavm.idea.jps.remote.TeaVMRemoteBuildService;
|
||||
import org.teavm.tooling.EmptyTeaVMToolLog;
|
||||
import org.teavm.tooling.TeaVMTool;
|
||||
import org.teavm.tooling.TeaVMToolException;
|
||||
import org.teavm.tooling.sources.DirectorySourceFileProvider;
|
||||
import org.teavm.tooling.sources.JarSourceFileProvider;
|
||||
import org.teavm.vm.TeaVMPhase;
|
||||
import org.teavm.vm.TeaVMProgressFeedback;
|
||||
import org.teavm.vm.TeaVMProgressListener;
|
||||
|
||||
public class TeaVMBuildDaemon extends UnicastRemoteObject implements TeaVMRemoteBuildService {
|
||||
private static final int MIN_PORT = 10000;
|
||||
private static final int MAX_PORT = 1 << 16;
|
||||
private static final Set<String> KOTLIN_FILES = new HashSet<>(Arrays.asList("teavm-jps-common.jar",
|
||||
"teavm-plugin.jar", "teavm.jar"));
|
||||
private static final String DAEMON_CLASS = TeaVMBuildDaemon.class.getName().replace('.', '/') + ".class";
|
||||
private static final int DAEMON_CLASS_DEPTH;
|
||||
private static final String DAEMON_MESSAGE_PREFIX = "TeaVM daemon port: ";
|
||||
private int port;
|
||||
private Registry registry;
|
||||
|
||||
static {
|
||||
int depth = 0;
|
||||
for (int i = 0; i < DAEMON_CLASS.length(); ++i) {
|
||||
if (DAEMON_CLASS.charAt(i) == '/') {
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
DAEMON_CLASS_DEPTH = depth;
|
||||
}
|
||||
|
||||
TeaVMBuildDaemon() 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(TeaVMRemoteBuildService.ID, this);
|
||||
} catch (RemoteException | AlreadyBoundException e) {
|
||||
throw new IllegalStateException("Could not bind remote build assistant service", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Could not create RMI registry");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws RemoteException {
|
||||
TeaVMBuildDaemon daemon = new TeaVMBuildDaemon();
|
||||
System.out.println(DAEMON_MESSAGE_PREFIX + daemon.port);
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMRemoteBuildResponse build(TeaVMRemoteBuildRequest request, TeaVMRemoteBuildCallback callback)
|
||||
throws RemoteException {
|
||||
TeaVMTool tool = new TeaVMTool();
|
||||
tool.setProgressListener(createProgressListener(callback));
|
||||
tool.setLog(new EmptyTeaVMToolLog());
|
||||
tool.setTargetType(request.targetType);
|
||||
tool.setMainClass(request.mainClass);
|
||||
tool.setTargetDirectory(new File(request.targetDirectory));
|
||||
tool.setClassLoader(buildClassLoader(request.classPath));
|
||||
|
||||
tool.setSourceMapsFileGenerated(request.sourceMapsFileGenerated);
|
||||
tool.setDebugInformationGenerated(request.debugInformationGenerated);
|
||||
tool.setSourceFilesCopied(request.sourceFilesCopied);
|
||||
|
||||
for (String sourceDirectory : request.sourceDirectories) {
|
||||
tool.addSourceFileProvider(new DirectorySourceFileProvider(new File(sourceDirectory)));
|
||||
}
|
||||
for (String sourceJar : request.sourceJarFiles) {
|
||||
tool.addSourceFileProvider(new JarSourceFileProvider(new File(sourceJar)));
|
||||
}
|
||||
|
||||
boolean errorOccurred = false;
|
||||
try {
|
||||
tool.generate();
|
||||
} catch (TeaVMToolException | RuntimeException | Error e) {
|
||||
e.printStackTrace(System.err);
|
||||
errorOccurred = true;
|
||||
}
|
||||
|
||||
TeaVMRemoteBuildResponse response = new TeaVMRemoteBuildResponse();
|
||||
response.errorOccurred = errorOccurred;
|
||||
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());
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private ClassLoader buildClassLoader(List<String> classPathEntries) {
|
||||
URL[] urls = classPathEntries.stream().map(entry -> {
|
||||
try {
|
||||
return new File(entry).toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(entry);
|
||||
}
|
||||
}).toArray(URL[]::new);
|
||||
|
||||
return new URLClassLoader(urls);
|
||||
}
|
||||
|
||||
private TeaVMProgressListener createProgressListener(TeaVMRemoteBuildCallback callback) {
|
||||
return new TeaVMProgressListener() {
|
||||
private long lastReportedTime;
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback phaseStarted(TeaVMPhase phase, int count) {
|
||||
if ((System.currentTimeMillis() - lastReportedTime) > 100) {
|
||||
lastReportedTime = System.currentTimeMillis();
|
||||
try {
|
||||
return callback.phaseStarted(phase, count);
|
||||
} catch (RemoteException e) {
|
||||
return TeaVMProgressFeedback.CANCEL;
|
||||
}
|
||||
} else {
|
||||
return TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeaVMProgressFeedback progressReached(int progress) {
|
||||
if ((System.currentTimeMillis() - lastReportedTime) > 100) {
|
||||
lastReportedTime = System.currentTimeMillis();
|
||||
try {
|
||||
return callback.progressReached(progress);
|
||||
} catch (RemoteException e) {
|
||||
return TeaVMProgressFeedback.CANCEL;
|
||||
}
|
||||
} else {
|
||||
return TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static TeaVMDaemonInfo start() throws IOException {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
String javaCommand = javaHome + "/bin/java";
|
||||
String classPath = detectClassPath().stream().collect(Collectors.joining(File.pathSeparator));
|
||||
ProcessBuilder builder = new ProcessBuilder(javaCommand, "-cp", classPath, TeaVMBuildDaemon.class.getName());
|
||||
Process process = builder.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
|
||||
String line = reader.readLine();
|
||||
if (line == null || !line.startsWith(DAEMON_MESSAGE_PREFIX)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
|
||||
while (true) {
|
||||
line = reader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
sb.append(line).append('\n');
|
||||
}
|
||||
throw new IllegalStateException("Could not start daemon. Stderr: " + sb);
|
||||
}
|
||||
int port = Integer.parseInt(line.substring(DAEMON_MESSAGE_PREFIX.length()));
|
||||
return new TeaVMDaemonInfo(port, process);
|
||||
}
|
||||
|
||||
private static List<String> detectClassPath() {
|
||||
IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginId.getId("org.teavm.idea"));
|
||||
Set<File> visited = new HashSet<>();
|
||||
List<String> classPath = new ArrayList<>();
|
||||
findInHierarchy(plugin.getPath(), classPath, visited);
|
||||
return classPath;
|
||||
}
|
||||
|
||||
private static void findInHierarchy(File file, List<String> targetFiles, Set<File> visited) {
|
||||
if (!visited.add(file)) {
|
||||
return;
|
||||
}
|
||||
if (file.isFile() && KOTLIN_FILES.contains(file.getName())) {
|
||||
targetFiles.add(file.getAbsolutePath());
|
||||
} else if (file.getPath().endsWith(DAEMON_CLASS)) {
|
||||
for (int i = 0; i <= DAEMON_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,34 @@
|
|||
/*
|
||||
* Copyright 2017 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.daemon;
|
||||
|
||||
public class TeaVMDaemonInfo {
|
||||
private int port;
|
||||
private Process process;
|
||||
|
||||
TeaVMDaemonInfo(int port, Process process) {
|
||||
this.port = port;
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public Process getProcess() {
|
||||
return process;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2017 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.ui;
|
||||
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.teavm.idea.TeaVMDaemonComponent;
|
||||
|
||||
public class TeaVMSettingsEditorTab implements SearchableConfigurable {
|
||||
private JPanel contentPane;
|
||||
private JCheckBox daemonCheckBox;
|
||||
private TeaVMDaemonComponent daemonComponent;
|
||||
|
||||
public TeaVMSettingsEditorTab(TeaVMDaemonComponent daemonComponent) {
|
||||
this.daemonComponent = daemonComponent;
|
||||
|
||||
contentPane = new JPanel();
|
||||
daemonCheckBox = new JCheckBox("use build daemon (can increase performance in most cases)");
|
||||
contentPane.setLayout(new GridBagLayout());
|
||||
|
||||
GridBagConstraints labelConstraints = new GridBagConstraints();
|
||||
labelConstraints.gridwidth = GridBagConstraints.REMAINDER;
|
||||
labelConstraints.anchor = GridBagConstraints.BASELINE_LEADING;
|
||||
labelConstraints.weightx = 1;
|
||||
labelConstraints.weighty = 1;
|
||||
labelConstraints.insets.left = 5;
|
||||
labelConstraints.insets.right = 5;
|
||||
|
||||
contentPane.add(daemonCheckBox, labelConstraints);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getId() {
|
||||
return "project.teavm.settings";
|
||||
}
|
||||
|
||||
@Nls
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "TeaVM";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getHelpTopic() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent createComponent() {
|
||||
return contentPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModified() {
|
||||
return daemonCheckBox.isSelected() != daemonComponent.isDaemonRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() throws ConfigurationException {
|
||||
if (daemonCheckBox.isSelected()) {
|
||||
daemonComponent.startDaemon();
|
||||
} else {
|
||||
daemonComponent.stopDaemon();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
daemonCheckBox.setSelected(daemonComponent.isDaemonRunning());
|
||||
}
|
||||
}
|
|
@ -7,13 +7,10 @@
|
|||
<depends>org.jetbrains.idea.maven</depends>
|
||||
|
||||
<description><![CDATA[
|
||||
Enter short description for your plugin here.<br>
|
||||
<em>most HTML tags may be used</em>
|
||||
Plugin that allows to run TeaVM compiler and debug applications generated by TeaVM.
|
||||
]]></description>
|
||||
|
||||
<change-notes><![CDATA[
|
||||
Add change notes here.<br>
|
||||
<em>most HTML tags may be used</em>
|
||||
]]>
|
||||
</change-notes>
|
||||
|
||||
|
@ -23,14 +20,24 @@
|
|||
<component>
|
||||
<implementation-class>org.teavm.idea.TeaVMJPSRemoteService</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.teavm.idea.TeaVMDaemonComponent</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<applicationService serviceImplementation="org.teavm.idea.TeaVMWorkspaceConfigurationStorage"/>
|
||||
|
||||
<compileServer.plugin classpath="jps/teavm-jps-plugin.jar;teavm.jar;teavm-jps-common.jar"/>
|
||||
<buildProcess.parametersProvider implementation="org.teavm.idea.TeaVMJPSConfigurator"/>
|
||||
<configurationType implementation="org.teavm.idea.debug.TeaVMDebugConfigurationType"/>
|
||||
<programRunner implementation="org.teavm.idea.debug.TeaVMDebugRunner"/>
|
||||
|
||||
<applicationConfigurable instance="org.teavm.idea.ui.TeaVMSettingsEditorTab"
|
||||
id="project.teavm.settings"
|
||||
displayName="TeaVM compiler"
|
||||
parentId="project.propCompiler"/>
|
||||
|
||||
<facetType implementation="org.teavm.idea.TeaVMFacetType"/>
|
||||
<facetType implementation="org.teavm.idea.TeaVMWebAssemblyFacetType"/>
|
||||
</extensions>
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
<root url="jar://$MODULE_DIR$/../idea-artifacts/dependencies/teavm.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
<SOURCES>
|
||||
<root url="file://$MODULE_DIR$/../../../core/src/main/java" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
|
|
Loading…
Reference in New Issue
Block a user