IDEA: refactor JPS plugin to allow proper redeployment in javaee plugin

This commit is contained in:
Alexey Andreev 2017-04-12 17:34:14 +03:00
parent 3ad16e80c7
commit 6a1dd17af9
11 changed files with 269 additions and 78 deletions

View File

@ -101,6 +101,7 @@ public class TeaVMTool implements BaseTeaVMTool {
private JavaScriptTarget javaScriptTarget;
private WasmTarget webAssemblyTarget;
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
private Set<File> generatedFiles = new HashSet<>();
public File getTargetDirectory() {
return targetDirectory;
@ -276,6 +277,10 @@ public class TeaVMTool implements BaseTeaVMTool {
return vm != null ? vm.getClasses() : Collections.emptyList();
}
public Set<File> getGeneratedFiles() {
return generatedFiles;
}
public Collection<String> getUsedResources() {
if (vm == null) {
return Collections.emptyList();
@ -443,6 +448,9 @@ public class TeaVMTool implements BaseTeaVMTool {
TeaVMProblemRenderer.describeProblems(vm, log);
}
File outputFile = new File(targetDirectory, outputName);
generatedFiles.add(outputFile);
if (targetType == TeaVMTargetType.JAVASCRIPT) {
try (OutputStream output = new FileOutputStream(new File(targetDirectory, outputName), true)) {
try (Writer writer = new OutputStreamWriter(output, "UTF-8")) {
@ -488,10 +496,11 @@ public class TeaVMTool implements BaseTeaVMTool {
if (debugInformationGenerated) {
assert debugEmitter != null;
DebugInformation debugInfo = debugEmitter.getDebugInformation();
try (OutputStream debugInfoOut = new BufferedOutputStream(new FileOutputStream(new File(targetDirectory,
getResolvedTargetFileName() + ".teavmdbg")))) {
File debugSymbolFile = new File(targetDirectory, getResolvedTargetFileName() + ".teavmdbg");
try (OutputStream debugInfoOut = new BufferedOutputStream(new FileOutputStream(debugSymbolFile))) {
debugInfo.write(debugInfoOut);
}
generatedFiles.add(debugSymbolFile);
log.info("Debug information successfully written");
}
if (sourceMapsFileGenerated) {
@ -499,8 +508,8 @@ public class TeaVMTool implements BaseTeaVMTool {
DebugInformation debugInfo = debugEmitter.getDebugInformation();
String sourceMapsFileName = getResolvedTargetFileName() + ".map";
writer.append("\n//# sourceMappingURL=").append(sourceMapsFileName);
try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream(
new File(targetDirectory, sourceMapsFileName)), "UTF-8")) {
File sourceMapsFile = new File(targetDirectory, sourceMapsFileName);
try (Writer sourceMapsOut = new OutputStreamWriter(new FileOutputStream(sourceMapsFile), "UTF-8")) {
debugInfo.writeAsSourceMaps(sourceMapsOut, "src", getResolvedTargetFileName());
}
log.info("Source maps successfully written");
@ -548,9 +557,11 @@ public class TeaVMTool implements BaseTeaVMTool {
private void resourceToFile(String resource, String fileName) throws IOException {
try (InputStream input = TeaVMTool.class.getClassLoader().getResourceAsStream(resource)) {
try (OutputStream output = new FileOutputStream(new File(targetDirectory, fileName))) {
File outputFile = new File(targetDirectory, fileName);
try (OutputStream output = new FileOutputStream(outputFile)) {
IOUtils.copy(input, output);
}
generatedFiles.add(outputFile);
}
}

View File

@ -29,4 +29,6 @@ public interface TeaVMBuildResult {
Collection<String> getUsedResources();
Collection<String> getClasses();
Collection<String> getGeneratedFiles();
}

View File

@ -30,4 +30,5 @@ public class TeaVMRemoteBuildResponse implements Serializable {
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<>();
}

View File

@ -21,6 +21,8 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.teavm.callgraph.CallGraph;
@ -137,8 +139,12 @@ public class InProcessBuildStrategy implements TeaVMBuildStrategy {
errorOccurred = true;
}
Set<String> generatedFiles = tool.getGeneratedFiles().stream()
.map(File::getAbsolutePath)
.collect(Collectors.toSet());
return new InProcessBuildResult(tool.getDependencyInfo().getCallGraph(), errorOccurred,
tool.getProblemProvider(), tool.getClasses(), tool.getUsedResources());
tool.getProblemProvider(), tool.getClasses(), tool.getUsedResources(), generatedFiles);
}
private ClassLoader buildClassLoader() {
@ -161,14 +167,16 @@ public class InProcessBuildStrategy implements TeaVMBuildStrategy {
private ProblemProvider problemProvider;
private Collection<String> classes;
private Collection<String> usedResources;
private Collection<String> generatedFiles;
InProcessBuildResult(CallGraph callGraph, boolean errorOccurred, ProblemProvider problemProvider,
Collection<String> classes, Collection<String> usedResources) {
Collection<String> classes, Collection<String> usedResources, Collection<String> generatedFiles) {
this.callGraph = callGraph;
this.errorOccurred = errorOccurred;
this.problemProvider = problemProvider;
this.classes = classes;
this.usedResources = usedResources;
this.generatedFiles = generatedFiles;
}
@Override
@ -195,5 +203,10 @@ public class InProcessBuildStrategy implements TeaVMBuildStrategy {
public Collection<String> getUsedResources() {
return usedResources;
}
@Override
public Collection<String> getGeneratedFiles() {
return generatedFiles;
}
}
}

View File

@ -142,6 +142,11 @@ public class RemoteBuildStrategy implements TeaVMBuildStrategy {
public Collection<String> getClasses() {
return response.classes;
}
@Override
public Collection<String> getGeneratedFiles() {
return response.generatedFiles;
}
};
}

View File

@ -34,8 +34,8 @@ import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.stream.Stream;
import org.jetbrains.jps.builders.BuildOutputConsumer;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.messages.BuildMessage;
import org.jetbrains.jps.incremental.messages.CompilerMessage;
import org.jetbrains.jps.incremental.messages.ProgressMessage;
@ -65,50 +65,35 @@ import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
import org.teavm.model.TextLocation;
import org.teavm.model.ValueType;
import org.teavm.tooling.TeaVMTargetType;
import org.teavm.vm.TeaVMPhase;
import org.teavm.vm.TeaVMProgressFeedback;
import org.teavm.vm.TeaVMProgressListener;
class TeaVMBuild {
private final CompileContext context;
private final TeaVMStorageProvider jsStorageProvider = new TeaVMStorageProvider("js");
private final TeaVMStorageProvider wasmStorageProvider = new TeaVMStorageProvider("wasm");
private final List<String> classPathEntries = new ArrayList<>();
private List<String> directoryClassPathEntries;
private Map<TeaVMTargetType, TeaVMStorage> storages = new HashMap<>();
private TeaVMStorage storage;
private final TeaVMBuilderAssistant assistant;
private final Map<String, File> sourceFileCache = new HashMap<>();
private final Map<File, int[]> fileLineCache = new HashMap<>();
private TeaVMBuildStrategy buildStrategy;
private BuildOutputConsumer outputConsumer;
TeaVMBuild(CompileContext context, TeaVMBuilderAssistant assistant, TeaVMBuildStrategy buildStrategy) {
TeaVMBuild(CompileContext context, TeaVMBuilderAssistant assistant, TeaVMBuildStrategy buildStrategy,
BuildOutputConsumer outputConsumer) {
this.context = context;
this.assistant = assistant;
this.buildStrategy = buildStrategy;
this.outputConsumer = outputConsumer;
}
boolean perform(JpsModule module, ModuleBuildTarget target) throws IOException {
storages.put(TeaVMTargetType.JAVASCRIPT, context.getProjectDescriptor().dataManager.getStorage(
target, jsStorageProvider));
storages.put(TeaVMTargetType.WEBASSEMBLY, context.getProjectDescriptor().dataManager.getStorage(
target, wasmStorageProvider));
boolean perform(JpsModule module, TeaVMBuildTarget target) throws IOException {
TeaVMStorageProvider storageProvider = new TeaVMStorageProvider(
target.getConfiguration().getTargetType().name());
storage = context.getProjectDescriptor().dataManager.getStorage(target, storageProvider);
boolean doneSomething = false;
for (TeaVMJpsConfiguration config : TeaVMJpsConfiguration.getAll(module)) {
if (performForSubsystem(module, target, config)) {
doneSomething = true;
}
}
return doneSomething;
}
private boolean performForSubsystem(JpsModule module, ModuleBuildTarget target, TeaVMJpsConfiguration config)
throws IOException {
if (config == null) {
return false;
}
TeaVMJpsConfiguration config = target.getConfiguration();
classPathEntries.clear();
buildStrategy.init();
@ -116,7 +101,7 @@ class TeaVMBuild {
directoryClassPathEntries = classPathEntries.stream().filter(name -> new File(name).isDirectory())
.collect(toList());
if (!hasChanges(target, config.getTargetType())) {
if (!hasChanges(target)) {
return false;
}
@ -131,11 +116,15 @@ class TeaVMBuild {
TeaVMBuildResult buildResult = buildStrategy.build();
if (!buildResult.isErrorOccurred() && buildResult.getProblems().getSevereProblems().isEmpty()) {
updateStorage(buildResult, config.getTargetType());
updateStorage(buildResult);
}
reportProblems(buildResult.getProblems(), buildResult.getCallGraph());
for (String fileName : buildResult.getGeneratedFiles()) {
outputConsumer.registerOutputFile(new File(fileName), Collections.emptyList());
}
return true;
}
@ -410,13 +399,13 @@ class TeaVMBuild {
return lines.getAll();
}
private boolean hasChanges(ModuleBuildTarget target, TeaVMTargetType targetType) {
private boolean hasChanges(TeaVMBuildTarget target) {
if (!context.getScope().isBuildIncrementally(target.getTargetType())
|| context.getScope().isBuildForced(target)) {
return true;
}
List<TeaVMStorage.Entry> filesToWatch = storages.get(targetType).getParticipatingFiles();
List<TeaVMStorage.Entry> filesToWatch = storage.getParticipatingFiles();
if (filesToWatch == null) {
return true;
}
@ -430,7 +419,7 @@ class TeaVMBuild {
return false;
}
private void updateStorage(TeaVMBuildResult buildResult, TeaVMTargetType targetType) {
private void updateStorage(TeaVMBuildResult buildResult) {
Set<String> resources = Stream.concat(buildResult.getClasses().stream()
.map(cls -> cls.replace('.', '/') + ".class"), buildResult.getUsedResources().stream())
.sorted()
@ -443,7 +432,7 @@ class TeaVMBuild {
.filter(Objects::nonNull)
.collect(toList());
storages.get(targetType).setParticipatingFiles(participatingFiles);
storage.setParticipatingFiles(participatingFiles);
}
private Long getTimestamp(String path) {

View File

@ -0,0 +1,93 @@
/*
* 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.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.BuildTarget;
import org.jetbrains.jps.builders.BuildTargetRegistry;
import org.jetbrains.jps.builders.ModuleBasedTarget;
import org.jetbrains.jps.builders.TargetOutputIndex;
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
import org.jetbrains.jps.builders.storage.BuildDataPaths;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.indices.IgnoredFileIndex;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.module.JpsModule;
import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
public class TeaVMBuildTarget extends ModuleBasedTarget<BuildRootDescriptor> {
private TeaVMJpsConfiguration configuration;
public TeaVMBuildTarget(TeaVMBuildTargetType targetType, @NotNull JpsModule module,
@NotNull TeaVMJpsConfiguration configuration) {
super(targetType, module);
this.configuration = configuration;
}
@Override
public boolean isTests() {
return false;
}
@Override
public String getId() {
return getModule().getName() + "-" + configuration.getTargetType().name();
}
@Override
public Collection<BuildTarget<?>> computeDependencies(BuildTargetRegistry targetRegistry,
TargetOutputIndex outputIndex) {
return Collections.singleton(new ModuleBuildTarget(myModule, JavaModuleBuildTargetType.PRODUCTION));
}
@NotNull
@Override
public List<BuildRootDescriptor> computeRootDescriptors(JpsModel model, ModuleExcludeIndex index,
IgnoredFileIndex ignoredFileIndex, BuildDataPaths dataPaths) {
return Collections.emptyList();
}
@Nullable
@Override
public BuildRootDescriptor findRootDescriptor(String rootId, BuildRootIndex rootIndex) {
return null;
}
@NotNull
@Override
public String getPresentableName() {
return "TeaVM configuration '" + getModule().getName() + "' - " + configuration.getTargetType();
}
@NotNull
@Override
public Collection<File> getOutputRoots(CompileContext context) {
return Collections.singleton(new File(configuration.getTargetDirectory()));
}
public TeaVMJpsConfiguration getConfiguration() {
return configuration;
}
}

View File

@ -0,0 +1,97 @@
/*
* 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.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.BuildTargetLoader;
import org.jetbrains.jps.builders.ModuleBasedBuildTargetType;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.module.JpsModule;
import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
import org.teavm.tooling.TeaVMTargetType;
public class TeaVMBuildTargetType extends ModuleBasedBuildTargetType<TeaVMBuildTarget> {
public static final String ID = "teavm";
public static final TeaVMBuildTargetType INSTANCE = new TeaVMBuildTargetType();
private TeaVMBuildTargetType() {
super(ID);
}
@NotNull
@Override
public List<TeaVMBuildTarget> computeAllTargets(@NotNull JpsModel model) {
List<TeaVMBuildTarget> targets = new ArrayList<>();
for (JpsModule module : model.getProject().getModules()) {
for (TeaVMJpsConfiguration config : TeaVMJpsConfiguration.getAll(module)) {
targets.add(new TeaVMBuildTarget(this, module, config));
}
}
return targets;
}
@NotNull
@Override
public BuildTargetLoader<TeaVMBuildTarget> createLoader(@NotNull JpsModel model) {
return new Loader(model);
}
class Loader extends BuildTargetLoader<TeaVMBuildTarget> {
private final Map<String, Configuration> modules;
public Loader(JpsModel model) {
modules = new HashMap<>();
for (JpsModule module : model.getProject().getModules()) {
for (TeaVMJpsConfiguration config : TeaVMJpsConfiguration.getAll(module)) {
modules.put(module.getName() + "-" + config.getTargetType().name(),
new Configuration(module, config.getTargetType()));
}
}
}
@Nullable
@Override
public TeaVMBuildTarget createTarget(@NotNull String targetId) {
Configuration configuration = modules.get(targetId);
if (configuration == null) {
return null;
}
for (TeaVMJpsConfiguration jpsConfig : TeaVMJpsConfiguration.getAll(configuration.module)) {
if (jpsConfig.getTargetType() == configuration.type) {
return new TeaVMBuildTarget(TeaVMBuildTargetType.this, configuration.module, jpsConfig);
}
}
return null;
}
}
class Configuration {
final JpsModule module;
final TeaVMTargetType type;
public Configuration(@NotNull JpsModule module, @NotNull TeaVMTargetType type) {
this.module = module;
this.type = type;
}
}
}

View File

@ -21,28 +21,26 @@ import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Collections;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.builders.BuildOutputConsumer;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor;
import org.jetbrains.jps.incremental.BuilderCategory;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ModuleBuildTarget;
import org.jetbrains.jps.incremental.ModuleLevelBuilder;
import org.jetbrains.jps.incremental.ProjectBuildException;
import org.jetbrains.jps.incremental.TargetBuilder;
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 {
public class TeaVMBuilder extends TargetBuilder<BuildRootDescriptor, TeaVMBuildTarget> {
private TeaVMBuilderAssistant assistant;
private TeaVMRemoteBuildService buildService;
public TeaVMBuilder() {
super(BuilderCategory.CLASS_POST_PROCESSOR);
super(Collections.singletonList(TeaVMBuildTargetType.INSTANCE));
String portString = System.getProperty(REMOTE_PORT);
if (portString != null) {
@ -66,28 +64,21 @@ public class TeaVMBuilder extends ModuleLevelBuilder {
}
@Override
public ExitCode build(CompileContext context, ModuleChunk chunk,
DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
OutputConsumer outputConsumer) throws ProjectBuildException, IOException {
public void build(@NotNull TeaVMBuildTarget target,
@NotNull DirtyFilesHolder<BuildRootDescriptor, TeaVMBuildTarget> holder,
@NotNull BuildOutputConsumer outputConsumer, @NotNull CompileContext context) throws ProjectBuildException,
IOException {
if (assistant == null) {
context.processMessage(new CompilerMessage("TeaVM", BuildMessage.Kind.WARNING,
"No TeaVM builder assistant available. Diagnostic messages will be less informative"));
}
boolean doneSomething = false;
TeaVMBuildStrategy buildStrategy = buildService != null
? new RemoteBuildStrategy(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()) {
return ExitCode.ABORT;
}
}
TeaVMBuild build = new TeaVMBuild(context, assistant, buildStrategy, outputConsumer);
return doneSomething ? ExitCode.OK : ExitCode.NOTHING_DONE;
build.perform(target.getModule(), target);
}
@NotNull

View File

@ -15,38 +15,24 @@
*/
package org.teavm.idea.jps;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.builders.BuildTargetType;
import org.jetbrains.jps.incremental.BuilderService;
import org.jetbrains.jps.incremental.ModuleLevelBuilder;
import org.jetbrains.jps.incremental.TargetBuilder;
public class TeaVMBuilderService extends BuilderService {
@NotNull
@Override
public List<? extends ModuleLevelBuilder> createModuleLevelBuilders() {
try {
Enumeration<URL> resources = TeaVMBuilderService.class.getClassLoader().getResources(
"org/objectweb/asm/ClassVisitor.class");
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
System.out.println(url);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println();
public List<? extends TargetBuilder<?, ?>> createBuilders() {
return Arrays.asList(new TeaVMBuilder());
}
@NotNull
@Override
public List<? extends TargetBuilder<?, ?>> createBuilders() {
return Collections.emptyList();
public List<? extends BuildTargetType<?>> getTargetTypes() {
return Collections.singletonList(TeaVMBuildTargetType.INSTANCE);
}
}

View File

@ -142,6 +142,9 @@ public class TeaVMBuildDaemon extends UnicastRemoteObject implements TeaVMRemote
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;
}