Running java scratches (IDEA-140228)

This commit is contained in:
Eugene Zhuravlev
2015-09-11 12:05:18 +02:00
parent bfda7d73b5
commit d65d572071
9 changed files with 668 additions and 137 deletions
@@ -0,0 +1,170 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* 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 com.intellij.execution.impl;
import com.intellij.compiler.options.CompileStepBeforeRun;
import com.intellij.execution.configurations.ModuleBasedConfiguration;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdk;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFileManager;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 08-Sep-15
*/
public class JavaScratchCompilationSupport implements ProjectComponent, CompileTask{
public JavaScratchCompilationSupport(Project project, CompilerManager compileManager) {
compileManager.addAfterTask(this);
}
@Override
public boolean execute(CompileContext context) {
final Project project = context.getProject();
File outputDir = null;
File srcDir = null;
if (context.isRebuild()) {
// perform cleanup
outputDir = JavaScratchRunConfigurationExtension.getScratchOutputDirectory(project);
if (outputDir == null) { // should not happen for normal projects
return true;
}
FileUtil.delete(outputDir);
srcDir = JavaScratchRunConfigurationExtension.getScratchTempDirectory(project);
if (srcDir != null) {
FileUtil.delete(srcDir);
}
}
final RunConfiguration configuration = CompileStepBeforeRun.getRunConfiguration(context);
if (!(configuration instanceof ModuleBasedConfiguration)) {
return true;
}
final String scratchUrl = JavaScratchRunConfigurationExtension.getScratchFileUrl(configuration);
if (scratchUrl == null) {
return true;
}
final Module configModule = ((ModuleBasedConfiguration)configuration).getConfigurationModule().getModule();
if (configModule == null) {
return true; // todo: show error?
}
final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(configModule);
final Sdk targetSdk = moduleRootManager.getSdk();
if (targetSdk == null || !(targetSdk.getSdkType() instanceof JavaSdkType)) {
return true; // todo: show error?
}
if (outputDir == null) {
outputDir = JavaScratchRunConfigurationExtension.getScratchOutputDirectory(project);
if (outputDir == null) { // should not happen for normal projects
return true;
}
}
try {
final File scratchFile = new File(VirtualFileManager.extractPath(scratchUrl));
File srcFile = scratchFile;
if (!StringUtil.endsWith(srcFile.getName(), ".java")) {
if (srcDir == null) {
srcDir = JavaScratchRunConfigurationExtension.getScratchTempDirectory(project);
if (srcDir == null) { // should not happen for normal projects
return true;
}
}
srcFile = new File(srcDir, FileUtil.getNameWithoutExtension(scratchFile) + ".java");
FileUtil.copy(scratchFile, srcFile);
}
final Collection<File> files = Collections.singleton(srcFile);
final Set<File> cp = new LinkedHashSet<File>();
for (String s : moduleRootManager.orderEntries().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList().getPathList()) {
cp.add(new File(s));
}
final List<File> platformCp = new ArrayList<File>();
for (String s : moduleRootManager.orderEntries().compileOnly().sdkOnly().getPathsList().getPathList()) {
platformCp.add(new File(s));
}
final List<String> options = new ArrayList<String>();
final JavaSdkVersion sdkVersion = JavaSdk.getInstance().getVersion(targetSdk);
if (sdkVersion != null) {
final String langLevel = "1." + Integer.valueOf(3 + sdkVersion.getMaxLanguageLevel().ordinal());
options.add("-source");
options.add(langLevel);
options.add("-target");
options.add(langLevel);
}
options.add("-proc:none"); // disable annotation processing
final Collection<ClassObject> result = CompilerManager.getInstance(project).compileJavaCode(
options, platformCp, cp, Collections.<File>emptyList(), files, outputDir
);
for (ClassObject classObject : result) {
final byte[] bytes = classObject.getContent();
if (bytes != null) {
FileUtil.writeToFile(new File(classObject.getPath()), bytes);
}
}
}
catch (CompilationException e) {
for (CompilationException.Message m : e.getMessages()) {
context.addMessage(m.getCategory(), m.getText(), scratchUrl, m.getLine(), m.getColumn());
}
}
catch (IOException e) {
context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), scratchUrl, -1, -1);
}
return true;
}
@Override
public void projectOpened() {
}
@Override
public void projectClosed() {
}
@Override
public void initComponent() {
}
@Override
public void disposeComponent() {
}
@NotNull
@Override
public String getComponentName() {
return "JavaScratchCompilationSupport";
}
}
@@ -0,0 +1,137 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* 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 com.intellij.execution.impl;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Location;
import com.intellij.execution.RunConfigurationExtension;
import com.intellij.execution.application.ApplicationConfiguration;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.configurations.RunnerSettings;
import com.intellij.ide.scratch.ScratchFileType;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
/*
execution-impl -> lang-impl(scratches are here)
compiler-impl -> lang-impl
java-impl ->execution-impl, compiler-impl
*/
public class JavaScratchRunConfigurationExtension extends RunConfigurationExtension{
public static final Key<String> SCRATCH_FILE_URL = Key.create("_scratch_file_path_");
public void cleanUserData(RunConfigurationBase configuration) {
super.cleanUserData(configuration);
configuration.putCopyableUserData(SCRATCH_FILE_URL, null);
}
protected void extendCreatedConfiguration(@NotNull RunConfigurationBase configuration, @NotNull Location location) {
final VirtualFile vFile = location.getVirtualFile();
if (vFile != null && vFile.getFileType() == ScratchFileType.INSTANCE) {
final PsiFile psiFile = location.getPsiElement().getContainingFile();
if (psiFile != null && psiFile.getLanguage() == JavaLanguage.INSTANCE) {
configuration.putCopyableUserData(SCRATCH_FILE_URL, vFile.getUrl());
}
}
}
protected void validateConfiguration(@NotNull RunConfigurationBase configuration, boolean isExecution) throws Exception {
super.validateConfiguration(configuration, isExecution);
}
public <T extends RunConfigurationBase> void updateJavaParameters(T configuration, JavaParameters params, RunnerSettings runnerSettings) throws ExecutionException {
final File scrachesOutput = getScratchOutputDirectory(configuration.getProject());
if (scrachesOutput != null) {
params.getClassPath().add(scrachesOutput);
}
}
@NotNull
protected String getSerializationId() {
return "java-scratch-properties";
}
@Nullable
public static String getScratchFileUrl(RunConfiguration configuration) {
return configuration instanceof RunConfigurationBase? ((RunConfigurationBase)configuration).getCopyableUserData(SCRATCH_FILE_URL) : null;
}
@Nullable
public static File getScratchOutputDirectory(Project project) {
final File root = CompilerManager.getInstance(project).getJavacCompilerWorkingDir();
return root != null? new File(root, "scratches/out") : null;
}
@Nullable
public static File getScratchTempDirectory(Project project) {
final File root = CompilerManager.getInstance(project).getJavacCompilerWorkingDir();
return root != null? new File(root, "scratches/src") : null;
}
protected void readExternal(@NotNull RunConfigurationBase runConfiguration, @NotNull Element element) throws InvalidDataException {
final Element sourceElement = element.getChild("source");
if (sourceElement != null) {
final String scratchUrl = sourceElement.getAttributeValue("url");
if (scratchUrl != null) {
runConfiguration.putCopyableUserData(SCRATCH_FILE_URL, scratchUrl);
}
}
}
protected void writeExternal(@NotNull RunConfigurationBase runConfiguration, @NotNull Element element) throws WriteExternalException {
final String url = getScratchFileUrl(runConfiguration);
if (url == null) {
super.writeExternal(runConfiguration, element);
}
else {
final Element urlElement = new Element("source");
urlElement.setAttribute("url", url);
element.addContent(urlElement);
}
}
@Nullable
protected <P extends RunConfigurationBase> SettingsEditor<P> createEditor(@NotNull P configuration) {
return null;
}
@Nullable
protected String getEditorTitle() {
return null;
}
protected boolean isApplicableFor(@NotNull RunConfigurationBase configuration) {
return configuration instanceof ApplicationConfiguration;
}
}