Fixing Enso projects classpath while updating to IGV 1.20 (#11195)

This commit is contained in:
Jaroslav Tulach 2024-10-01 13:48:50 +02:00 committed by GitHub
parent 6ea716f1b3
commit 7f9cf7a916
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 210 additions and 20 deletions

1
.gitignore vendored
View File

@ -97,6 +97,7 @@ bench-report*.xml
/built-distribution/
/enso
/ensoup
/project-manager
/enso.exp
/enso.lib

View File

@ -0,0 +1,99 @@
package org.enso.common;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Properties;
import org.junit.Test;
public class EnsoSourcesTest {
@Test
public void verifyEngineCommonSourcesFile() throws Exception {
var url = EnsoSourcesTest.class.getProtectionDomain().getCodeSource().getLocation();
var where = new File(url.toURI());
var engineCommonDir = findParentDir(where, ".enso-sources");
var mainSrc = loadProps(file(engineCommonDir, ".enso-sources-classes"));
var mainInput = mainSrc.get("input");
assertEquals(
"Points to src/main/java",
file(engineCommonDir, "src", "main", "java").toString(),
mainInput);
var testSrc = loadProps(file(engineCommonDir, ".enso-sources-test-classes"));
var testInput = testSrc.get("input");
assertEquals(
"Points to src/test/java",
file(engineCommonDir, "src", "test", "java").toString(),
testInput);
}
@Test
public void verifyScalaOnlyModularProject() throws Exception {
var url = EnsoSourcesTest.class.getProtectionDomain().getCodeSource().getLocation();
var where = new File(url.toURI());
var rootDir = findParentDir(where, "lib", "scala", "edition-updater");
var updaterDir = file(rootDir, "lib", "scala", "edition-updater");
var mainEnsoSources = file(updaterDir, ".enso-sources-classes");
assertTrue(
"This file should exists: "
+ mainEnsoSources
+ " - have you compiled edition-updater project?",
mainEnsoSources.exists());
var mainSrc = loadProps(mainEnsoSources);
var mainInput = mainSrc.get("input");
assertEquals(
"Points to src/main/java", file(updaterDir, "src", "main", "java").toString(), mainInput);
var testEnsoSources = file(updaterDir, ".enso-sources-test-classes");
assertFalse(
"No Java tests in this project. Checking " + testEnsoSources, testEnsoSources.exists());
}
@Test
public void verifyWrappersProject() throws Exception {
var url = EnsoSourcesTest.class.getProtectionDomain().getCodeSource().getLocation();
var where = new File(url.toURI());
var rootDir = findParentDir(where, "lib", "java", "fansi-wrapper");
var updaterDir = file(rootDir, "lib", "java", "fansi-wrapper");
var mainEnsoSources = file(updaterDir, ".enso-sources-classes");
assertTrue(
"This file should exists: "
+ mainEnsoSources
+ " - have you compiled fansi-wrapper project?",
mainEnsoSources.exists());
var mainSrc = loadProps(mainEnsoSources);
var mainInput = mainSrc.get("input");
assertEquals(
"Points to src/main/java", file(updaterDir, "src", "main", "java").toString(), mainInput);
var testEnsoSources = file(updaterDir, ".enso-sources-test-classes");
assertFalse(
"No Java tests in this project. Checking " + testEnsoSources, testEnsoSources.exists());
}
private Properties loadProps(File src) throws IOException {
var props = new Properties();
props.load(new FileInputStream(src));
return props;
}
private static File findParentDir(File root, String... names) {
for (var d = root; d != null; d = d.getParentFile()) {
var f = file(d, names);
if (f.exists()) {
return d;
}
}
throw new AssertionError(
"Cannot find " + Arrays.toString(names) + " in parent directories of " + root);
}
private static File file(File root, String... children) {
for (var ch : children) {
root = new File(root, ch);
}
return root;
}
}

View File

@ -137,9 +137,21 @@ object FrgaalJavaCompiler {
}
ap
}
val moduleInfoAndSources =
sources0.partition(_.toString().endsWith("module-info.java"))
val sourcesNoModuleInfo = moduleInfoAndSources._2
val out = output.getSingleOutputAsPath().get()
val shared = sources0.fold(out)(asCommon).asInstanceOf[Path]
val out = output.getSingleOutputAsPath().get()
val shared = sources0.fold(out)(asCommon).asInstanceOf[Path]
log.debug(
s"[FrgaalJavaCompiler] sources0: ${sources0}"
)
log.debug(
s"[FrgaalJavaCompiler] sourcesNoModuleInfo: ${sourcesNoModuleInfo}"
)
log.debug(
s"[FrgaalJavaCompiler] shared: ${shared}"
)
val allSources = if (shouldCompileModuleInfo) {
val moduleInfo = javaSourceDir.toPath.resolve("module-info.java").toFile
@ -197,17 +209,28 @@ object FrgaalJavaCompiler {
inATargetDir
}
val (withTarget, noTarget) = sources0.partition(checkTarget)
val (withTarget, noTarget) = sourcesNoModuleInfo
.partition(checkTarget)
log.debug(
s"[FrgaalJavaCompiler] withTarget: ${withTarget}"
)
log.debug(
s"[FrgaalJavaCompiler] noTarget: ${noTarget}"
)
val in = if (noTarget.isEmpty) {
None
log.debug(s"No target. Using location of ${moduleInfoAndSources._1}")
moduleInfoAndSources._1.map(asPath(_).getParent()).headOption
} else {
Some(
findUnder(
1,
3,
noTarget.tail.fold(asPath(noTarget.head))(asCommon).asInstanceOf[Path]
)
)
}
log.debug(
s"[FrgaalJavaCompiler] input sources are at: ${in}"
)
val generated = if (withTarget.isEmpty) {
None
} else {
@ -220,6 +243,9 @@ object FrgaalJavaCompiler {
)
)
}
log.debug(
s"[FrgaalJavaCompiler] generated code is at ${generated}"
)
if (shared.toFile().exists()) {
val ensoMarker = new File(shared.toFile(), ENSO_SOURCES)
@ -227,6 +253,9 @@ object FrgaalJavaCompiler {
shared.toFile(),
ENSO_SOURCES + "-" + out.getFileName().toString()
)
log.debug(
s"[FrgaalJavaCompiler] writing compiler configuration into ${ensoConfig}"
)
val ensoProperties = new java.util.Properties()
def storeArray(name: String, values: Seq[String]) = {
@ -302,7 +331,9 @@ object FrgaalJavaCompiler {
" You should attach the debugger now."
)
}
log.debug("[frgaal] Running " + (exe +: forkArgs).mkString(" "))
log.debug(
"[FrgaalJavaCompiler] Running " + (exe +: forkArgs).mkString(" ")
)
try {
exitCode = Process(exe +: forkArgs, cwd) ! javacLogger
} finally {

View File

@ -17,9 +17,9 @@ major operating systems.
## Installation
Visit [GraalVM's IGV page](https://www.graalvm.org/jdk22/tools/igv/) to read and
Visit [GraalVM's IGV page](https://www.graalvm.org/22.1/tools/igv/) to read and
download _IGV_. Or follow
[this link](https://lafo.ssw.uni-linz.ac.at/pub/idealgraphvisualizer/idealgraphvisualizer-0.31-cb98bbf5fef-all.zip)
[this link](https://lafo.ssw.uni-linz.ac.at/pub/idealgraphvisualizer/idealgraphvisualizer-1.20-ea624c6066a.zip)
to get ZIP with the most up to date version of _Ideal Graph Visualizer_ (as of
June 2024). Then:

View File

@ -1,6 +1,7 @@
package org.enso.tools.enso4igv;
import com.sun.jdi.connect.Connector;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
@ -10,6 +11,7 @@ import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.Future;
import java.util.prefs.Preferences;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.ListeningDICookie;
import org.netbeans.api.extexecution.ExecutionDescriptor;
@ -26,8 +28,11 @@ import org.netbeans.api.extexecution.base.ProcessBuilder;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.spi.project.ActionProgress;
import org.openide.awt.Notification;
import org.openide.awt.NotificationDisplayer;
import org.openide.filesystems.FileUtil;
import org.openide.modules.Modules;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.openide.util.RequestProcessor;
@ -40,7 +45,10 @@ import org.openide.windows.IOProvider;
"MSG_CannotExecute=Cannot execute {0}",
"# {0} - executable file",
"# {1} - exit code",
"MSG_ExecutionError=Process {0} finished with exit code {1}"
"MSG_ExecutionError=Process {0} finished with exit code {1}.",
"MSG_IgvMode=Enso/IGV Integration",
"MSG_EnableIgvMode=Send compiler graphs to IGV next time?",
"MSG_EnableIgvModeDone=Run Enso file again to get compiler graphs."
})
@ServiceProvider(service = ActionProvider.class)
public final class EnsoActionProvider implements ActionProvider {
@ -86,8 +94,19 @@ public final class EnsoActionProvider implements ActionProvider {
b.setRedirectErrorStream(true);
var env = b.getEnvironment();
if (isGraalVM && isIGVConnected()) {
env.setVariable("JAVA_OPTS", "-Dgraal.Dump=Truffle:2");
var info = IgvInfo.find();
if (isGraalVM && info.igvMode()) {
if (info.networkOn()) {
env.setVariable("JAVA_OPTS", info.toJavaOptions());
} else {
var icon = ImageUtilities.loadImageIcon("org/enso/tools/enso4igv/enso.svg", false);
var note = new Notification[1];
note[0] = NotificationDisplayer.getDefault().notify(Bundle.MSG_IgvMode(), icon, Bundle.MSG_EnableIgvMode(), (e) -> {
note[0].clear();
info.enableNetworkMode();
NotificationDisplayer.getDefault().notify(Bundle.MSG_IgvMode(), icon, Bundle.MSG_EnableIgvModeDone(), null);
});
}
}
var path = env.getVariable("PATH");
if (path != null && java != null) {
@ -107,11 +126,15 @@ public final class EnsoActionProvider implements ActionProvider {
var waitForProcessFuture = builderFuture.thenCompose((builder) -> {
var cf = new CompletableFuture<Integer>();
var descriptor = new ExecutionDescriptor()
.frontWindow(true).controllable(true)
.inputOutput(io)
.frontWindow(true)
.postExecution((exitCode) -> {
cf.complete(exitCode);
});
if (GraphicsEnvironment.isHeadless()) {
descriptor = descriptor.inputOutput(io);
} else {
descriptor = descriptor.controllable(true);
}
var launch = COMMAND_DEBUG_SINGLE.equals(action) || COMMAND_DEBUG.equals(action) ?
new DebugAndLaunch(fo, builder, params) : builder;
var service = ExecutionService.newService(launch, descriptor, script.getName());
@ -120,12 +143,20 @@ public final class EnsoActionProvider implements ActionProvider {
});
waitForProcessFuture.thenAcceptBoth(builderFuture, (exitCode, builder) -> {
if (exitCode != 0) {
var msg = Bundle.MSG_ExecutionError(builder.getDescription(), exitCode);
var md = new NotifyDescriptor.Message(msg, NotifyDescriptor.ERROR_MESSAGE);
dd.notifyLater(md);
boolean success;
if (exitCode != null) {
if (exitCode != 0) {
var msg = Bundle.MSG_ExecutionError(builder.getDescription(), exitCode);
var md = new NotifyDescriptor.Message(msg, NotifyDescriptor.ERROR_MESSAGE);
dd.notifyLater(md);
success = false;
} else {
success = true;
}
} else {
success = false;
}
process.finished(exitCode == 0);
process.finished(success);
}).exceptionally((ex) -> {
process.finished(false);
if (ex instanceof CompletionException && ex.getCause() instanceof CancellationException) {
@ -136,10 +167,38 @@ public final class EnsoActionProvider implements ActionProvider {
});
}
private static boolean isIGVConnected() {
return Modules.getDefault().findCodeNameBase("org.graalvm.visualizer.connection") != null;
record IgvInfo(boolean igvMode, boolean networkOn, int networkPort) {
static IgvInfo find() {
if (Modules.getDefault().findCodeNameBase("org.graalvm.visualizer.settings") != null) {
var settings = settingsNode();
var port = settings.getInt("portBinary", -1);
var network = settings.getBoolean("acceptNetwork", false);
return new IgvInfo(true, network, port);
} else {
return new IgvInfo(false, false, -1);
}
}
private static Preferences settingsNode() {
return Preferences.userRoot().node("org/graalvm/visualizer/settings/graal");
}
private String toJavaOptions() {
return
"-Dgraal.Dump=Truffle:2 " +
"-Djdk.graal.Dump=Truffle:2 " +
"-Dgraal.PrintGraph=Network " +
"-Djdk.graal.PrintGraph=Network " +
"-Dgraal.PrintGraphPort=" + networkPort() + " " +
"-Djdk.graal.PrintGraphPort=" + networkPort();
}
private void enableNetworkMode() {
settingsNode().putBoolean("acceptNetwork", true);
}
}
private static List<String> prepareArguments(File script) {
var list = new ArrayList<String>();
list.add("--run");