diff --git a/build.sbt b/build.sbt index a7cdfa4f85..c478d6cd0b 100644 --- a/build.sbt +++ b/build.sbt @@ -306,6 +306,7 @@ lazy val enso = (project in file(".")) `akka-native`, `version-output`, `refactoring-utils`, + `engine-runner-common`, `engine-runner`, runtime, searcher, @@ -1508,25 +1509,26 @@ lazy val `language-server` = (project in file("engine/language-server")) commands += WithDebugCommand.withDebug, frgaalJavaCompilerSetting, libraryDependencies ++= akka ++ circe ++ Seq( - "org.slf4j" % "slf4j-api" % slf4jVersion, - "com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion, - "io.circe" %% "circe-generic-extras" % circeGenericExtrasVersion, - "io.circe" %% "circe-literal" % circeVersion, - "dev.zio" %% "zio" % zioVersion, - "com.google.flatbuffers" % "flatbuffers-java" % flatbuffersVersion, - "commons-io" % "commons-io" % commonsIoVersion, - "com.github.pureconfig" %% "pureconfig" % pureconfigVersion, + "org.slf4j" % "slf4j-api" % slf4jVersion, + "com.typesafe.scala-logging" %% "scala-logging" % scalaLoggingVersion, + "io.circe" %% "circe-generic-extras" % circeGenericExtrasVersion, + "io.circe" %% "circe-literal" % circeVersion, + "dev.zio" %% "zio" % zioVersion, + "com.google.flatbuffers" % "flatbuffers-java" % flatbuffersVersion, + "commons-io" % "commons-io" % commonsIoVersion, + "com.github.pureconfig" %% "pureconfig" % pureconfigVersion, akkaTestkit % Test, - "com.typesafe.akka" %% "akka-http-testkit" % akkaHTTPVersion % Test, - "org.scalatest" %% "scalatest" % scalatestVersion % Test, - "org.scalacheck" %% "scalacheck" % scalacheckVersion % Test, - "org.graalvm.truffle" % "truffle-api" % graalMavenPackagesVersion % "provided", - "org.graalvm.sdk" % "polyglot-tck" % graalMavenPackagesVersion % "provided", - "org.eclipse.jgit" % "org.eclipse.jgit" % jgitVersion, - "org.bouncycastle" % "bcutil-jdk18on" % "1.76" % Test, - "org.bouncycastle" % "bcpkix-jdk18on" % "1.76" % Test, - "org.bouncycastle" % "bcprov-jdk18on" % "1.76" % Test, - "org.apache.tika" % "tika-core" % tikaVersion % Test + "com.typesafe.akka" %% "akka-http-testkit" % akkaHTTPVersion % Test, + "org.scalatest" %% "scalatest" % scalatestVersion % Test, + "org.scalacheck" %% "scalacheck" % scalacheckVersion % Test, + "org.graalvm.truffle" % "truffle-api" % graalMavenPackagesVersion % "provided", + "org.graalvm.sdk" % "polyglot-tck" % graalMavenPackagesVersion % "provided", + "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided", + "org.eclipse.jgit" % "org.eclipse.jgit" % jgitVersion, + "org.bouncycastle" % "bcutil-jdk18on" % "1.76" % Test, + "org.bouncycastle" % "bcpkix-jdk18on" % "1.76" % Test, + "org.bouncycastle" % "bcprov-jdk18on" % "1.76" % Test, + "org.apache.tika" % "tika-core" % tikaVersion % Test ), Test / testOptions += Tests .Argument(TestFrameworks.ScalaCheck, "-minSuccessfulTests", "1000"), @@ -1660,6 +1662,7 @@ lazy val `language-server` = (project in file("engine/language-server")) .dependsOn(`library-manager`) .dependsOn(`connected-lock-manager-server`) .dependsOn(`edition-updater`) + .dependsOn(`engine-runner-common`) .dependsOn(`logging-utils-akka`) .dependsOn(`logging-service`) .dependsOn(`polyglot-api`) @@ -2459,6 +2462,37 @@ lazy val `runtime-fat-jar` = * recompilation but still convince the IDE that it is a .jar dependency. */ +/* The purpose of the `engine-runner-common` project is to contain everything + * that's needed for the `engine-runner` project to invoke `language-server` when + * `--server` option is used. + * + * As such this project contains (primarily) the `LanguageServerApi` + * API & SPI class. `engine-runner` project call the `LanguageServerApi` class static method + * and that method then delegates to an implementation which is supposed to be provided + * by the `language-server` project. + * + * `engine-runner` and `language-server` projects shall be "loosely coupled" - they shouldn't + * have compile time dependency between each other. All that's needed for them to + * communicate belongs into `engine-runner-common` project. + */ +lazy val `engine-runner-common` = project + .in(file("engine/runner-common")) + .settings( + frgaalJavaCompilerSetting, + Test / fork := true, + commands += WithDebugCommand.withDebug, + Test / envVars ++= distributionEnvironmentOverrides, + libraryDependencies ++= Seq( + "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion % "provided", + "commons-io" % "commons-io" % commonsIoVersion, + "commons-cli" % "commons-cli" % commonsCliVersion + ) + ) + .dependsOn(`polyglot-api`) + .dependsOn(`library-manager`) + .dependsOn(`edition-updater`) + .dependsOn(testkit % Test) + lazy val `engine-runner` = project .in(file("engine/runner")) .settings( @@ -2684,14 +2718,16 @@ lazy val `engine-runner` = project .dependsOn(yaml) .dependsOn(pkg) .dependsOn(cli) + .dependsOn(`profiling-utils`) .dependsOn(`library-manager`) - .dependsOn(`language-server`) .dependsOn(`edition-updater`) .dependsOn(`runtime-parser`) .dependsOn(`logging-service`) .dependsOn(`logging-service-logback` % Runtime) + .dependsOn(`engine-runner-common`) .dependsOn(`polyglot-api`) .dependsOn(`enso-test-java-helpers`) + .dependsOn(`language-server` % Runtime) lazy val buildSmallJdk = taskKey[File]("Build a minimal JDK used for native image generation") diff --git a/engine/language-server/src/main/java/org/enso/languageserver/boot/LanguageServerRunner.java b/engine/language-server/src/main/java/org/enso/languageserver/boot/LanguageServerRunner.java new file mode 100644 index 0000000000..6f86104b88 --- /dev/null +++ b/engine/language-server/src/main/java/org/enso/languageserver/boot/LanguageServerRunner.java @@ -0,0 +1,89 @@ +package org.enso.languageserver.boot; + +import java.util.UUID; +import org.apache.commons.cli.CommandLine; +import org.enso.runner.common.LanguageServerApi; +import org.enso.runner.common.ProfilingConfig; +import org.enso.runner.common.WrongOption; +import org.openide.util.lookup.ServiceProvider; +import org.slf4j.event.Level; +import scala.concurrent.ExecutionContext; + +@ServiceProvider(service = LanguageServerApi.class) +public final class LanguageServerRunner extends LanguageServerApi { + public LanguageServerRunner() {} + + /** + * Handles `--server` CLI option + * + * @param line a CLI line + * @param prof profiling config + * @param logLevel log level to set for the engine runtime + */ + protected final void runLanguageServer(CommandLine line, ProfilingConfig prof, Level logLevel) + throws WrongOption { + var config = parseServerOptions(line, prof); + LanguageServerApp.run(config, logLevel, line.hasOption(LanguageServerApi.DAEMONIZE_OPTION)); + } + + private static LanguageServerConfig parseServerOptions( + CommandLine line, ProfilingConfig profilingConfig) throws WrongOption { + UUID rootId; + try { + var id = line.getOptionValue(LanguageServerApi.ROOT_ID_OPTION); + if (id == null) { + throw new WrongOption("Root id must be provided"); + } + rootId = UUID.fromString(id); + } catch (IllegalArgumentException e) { + throw new WrongOption("Root must be UUID"); + } + var rootPath = line.getOptionValue(LanguageServerApi.ROOT_PATH_OPTION); + if (rootPath == null) { + throw new WrongOption("Root path must be provided"); + } + var interfac = line.getOptionValue(LanguageServerApi.INTERFACE_OPTION, "127.0.0.1"); + int rpcPort; + try { + rpcPort = Integer.parseInt(line.getOptionValue(LanguageServerApi.RPC_PORT_OPTION, "8080")); + } catch (NumberFormatException e) { + throw new WrongOption("Port must be integer"); + } + int dataPort; + try { + dataPort = Integer.parseInt(line.getOptionValue(LanguageServerApi.DATA_PORT_OPTION, "8081")); + } catch (NumberFormatException e) { + throw new WrongOption("Port must be integer"); + } + Integer secureRpcPort; + try { + var port = line.getOptionValue(LanguageServerApi.SECURE_RPC_PORT_OPTION); + secureRpcPort = port == null ? null : Integer.valueOf(port); + } catch (NumberFormatException e) { + throw new WrongOption("Port must be integer"); + } + Integer secureDataPort; + try { + var port = line.getOptionValue(LanguageServerApi.SECURE_DATA_PORT_OPTION); + secureDataPort = port == null ? null : Integer.valueOf(port); + } catch (NumberFormatException e) { + throw new WrongOption("Port must be integer"); + } + var graalVMUpdater = line.hasOption(LanguageServerApi.SKIP_GRAALVM_UPDATER); + + var config = + new LanguageServerConfig( + interfac, + rpcPort, + scala.Option.apply(secureRpcPort), + dataPort, + scala.Option.apply(secureDataPort), + rootId, + rootPath, + profilingConfig, + new StartupConfig(graalVMUpdater), + "language-server", + ExecutionContext.global()); + return config; + } +} diff --git a/engine/runner/src/main/scala/org/enso/runner/LanguageServerApp.scala b/engine/language-server/src/main/scala/org/enso/languageserver/boot/LanguageServerApp.scala similarity index 98% rename from engine/runner/src/main/scala/org/enso/runner/LanguageServerApp.scala rename to engine/language-server/src/main/scala/org/enso/languageserver/boot/LanguageServerApp.scala index a510c28304..76eebbc9fe 100644 --- a/engine/runner/src/main/scala/org/enso/runner/LanguageServerApp.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/boot/LanguageServerApp.scala @@ -1,4 +1,4 @@ -package org.enso.runner +package org.enso.languageserver.boot import com.typesafe.scalalogging.Logger import org.enso.languageserver.boot.{ diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/boot/LanguageServerConfig.scala b/engine/language-server/src/main/scala/org/enso/languageserver/boot/LanguageServerConfig.scala index 90ffd88165..84d8c628f6 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/boot/LanguageServerConfig.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/boot/LanguageServerConfig.scala @@ -2,6 +2,7 @@ package org.enso.languageserver.boot import java.util.UUID +import org.enso.runner.common.ProfilingConfig import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} /** The config of the running Language Server instance. diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala b/engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala index e180b34bab..8151d99e57 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/boot/MainModule.scala @@ -12,6 +12,7 @@ import org.enso.editions.EditionResolver import org.enso.editions.updater.EditionManager import org.enso.filewatcher.WatcherAdapterFactory import org.enso.jsonrpc.{JsonRpcServer, SecureConnectionConfig} +import org.enso.runner.common.CompilerBasedDependencyExtractor import org.enso.languageserver.capability.CapabilityRouter import org.enso.languageserver.data._ import org.enso.languageserver.effect diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/data/Config.scala b/engine/language-server/src/main/scala/org/enso/languageserver/data/Config.scala index c319337dcd..13e073d22f 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/data/Config.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/data/Config.scala @@ -1,6 +1,7 @@ package org.enso.languageserver.data -import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} +import org.enso.runner.common.ProfilingConfig +import org.enso.languageserver.boot.StartupConfig import org.enso.languageserver.filemanager.ContentRootWithFile import org.enso.logger.masking.{MaskedPath, ToLogString} diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/libraries/handler/LibraryPublishHandler.scala b/engine/language-server/src/main/scala/org/enso/languageserver/libraries/handler/LibraryPublishHandler.scala index cb715bdc19..3396430bfa 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/libraries/handler/LibraryPublishHandler.scala +++ b/engine/language-server/src/main/scala/org/enso/languageserver/libraries/handler/LibraryPublishHandler.scala @@ -12,10 +12,8 @@ import org.enso.languageserver.libraries.LocalLibraryManagerProtocol.{ FindLibrary, FindLibraryResponse } -import org.enso.languageserver.libraries.{ - BlockingOperation, - CompilerBasedDependencyExtractor -} +import org.enso.runner.common.CompilerBasedDependencyExtractor +import org.enso.languageserver.libraries.BlockingOperation import org.enso.languageserver.requesthandler.RequestTimeout import org.enso.languageserver.util.UnhandledLogging import org.enso.libraryupload.{auth, LibraryUploader} diff --git a/engine/language-server/src/test/java/org/enso/languageserver/LanguageServerDependenciesTest.java b/engine/language-server/src/test/java/org/enso/languageserver/LanguageServerDependenciesTest.java new file mode 100644 index 0000000000..6db20b855d --- /dev/null +++ b/engine/language-server/src/test/java/org/enso/languageserver/LanguageServerDependenciesTest.java @@ -0,0 +1,30 @@ +package org.enso.languageserver; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import org.junit.Test; + +public class LanguageServerDependenciesTest { + + public LanguageServerDependenciesTest() {} + + @Test + public void unableToLoadClassFromEngineRunnerProject() { + try { + var c = Class.forName("org.enso.runner.Main"); + fail("Shouldn't be able to load class from engine-runner project " + c); + } catch (ClassNotFoundException ex) { + // OK + } + } + + @Test + public void ableToLoadClassFromEngineRunnerCommonProject() throws ClassNotFoundException { + var c = Class.forName("org.enso.runner.common.LanguageServerApi"); + assertNotNull( + "Should be able to load class from engine-runner-common project (obviously as we have" + + " compile time dependency)", + c); + } +} diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/boot/resource/RepoInitializationSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/boot/resource/RepoInitializationSpec.scala index 5e81d587c8..317d6c6572 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/boot/resource/RepoInitializationSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/boot/resource/RepoInitializationSpec.scala @@ -3,7 +3,8 @@ package org.enso.languageserver.boot.resource import akka.actor.ActorSystem import akka.testkit._ import org.apache.commons.io.FileUtils -import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} +import org.enso.runner.common.ProfilingConfig +import org.enso.languageserver.boot.StartupConfig import org.enso.languageserver.data._ import org.enso.languageserver.event.InitializedEvent import org.enso.languageserver.filemanager.{ContentRoot, ContentRootWithFile} diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootManagerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootManagerSpec.scala index 633a0154a3..a7134f4af5 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootManagerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/filemanager/ContentRootManagerSpec.scala @@ -3,7 +3,8 @@ package org.enso.languageserver.filemanager import akka.actor.{ActorRef, ActorSystem} import akka.testkit.{TestDuration, TestKit, TestProbe} import org.apache.commons.lang3.SystemUtils -import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} +import org.enso.runner.common.ProfilingConfig +import org.enso.languageserver.boot.StartupConfig import org.enso.languageserver.data._ import org.enso.languageserver.filemanager.ContentRootManagerProtocol.{ ContentRootsAddedNotification, diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala index 8b7cb7e175..0e78c9e6cf 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/runtime/ContextEventsListenerSpec.scala @@ -3,7 +3,8 @@ package org.enso.languageserver.runtime import akka.actor.{ActorRef, ActorSystem} import akka.testkit.{ImplicitSender, TestKit, TestProbe} import org.apache.commons.io.FileUtils -import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} +import org.enso.runner.common.ProfilingConfig +import org.enso.languageserver.boot.StartupConfig import org.enso.languageserver.data._ import org.enso.languageserver.filemanager.{ ContentRoot, diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala index 4c14bb94f9..f2a590c642 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/search/SuggestionsHandlerSpec.scala @@ -3,7 +3,8 @@ package org.enso.languageserver.search import akka.actor.{ActorRef, ActorSystem} import akka.testkit.{ImplicitSender, TestKit, TestProbe} import org.apache.commons.io.FileUtils -import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} +import org.enso.runner.common.ProfilingConfig +import org.enso.languageserver.boot.StartupConfig import org.enso.languageserver.capability.CapabilityProtocol.{ AcquireCapability, CapabilityAcquired diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BaseBinaryServerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BaseBinaryServerTest.scala index 672acd8e8a..cf5513b5eb 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BaseBinaryServerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/binary/BaseBinaryServerTest.scala @@ -6,7 +6,8 @@ import akka.actor.{ActorRef, Props} import akka.http.scaladsl.model.RemoteAddress import com.google.flatbuffers.FlatBufferBuilder import org.apache.commons.io.FileUtils -import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} +import org.enso.runner.common.ProfilingConfig +import org.enso.languageserver.boot.StartupConfig import org.enso.languageserver.data.{ Config, ExecutionContextConfig, diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala index 2a88021513..bb874d78fc 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/BaseServerTest.scala @@ -14,11 +14,9 @@ import org.enso.filewatcher.{NoopWatcherFactory, WatcherAdapterFactory} import org.enso.jsonrpc.test.JsonRpcServerTestKit import org.enso.jsonrpc.{ClientControllerFactory, ProtocolFactory} import org.enso.languageserver.TestClock -import org.enso.languageserver.boot.{ - ProfilingConfig, - StartupConfig, - TimingsConfig -} +import org.enso.runner.common.ProfilingConfig +import org.enso.runner.common.CompilerBasedDependencyExtractor +import org.enso.languageserver.boot.{StartupConfig, TimingsConfig} import org.enso.languageserver.boot.resource.{ DirectoriesInitialization, InitializationComponent, diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileManagerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileManagerTest.scala index 479746fb95..6635b76ac3 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileManagerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/FileManagerTest.scala @@ -4,7 +4,8 @@ import io.circe.literal._ import io.circe.parser.parse import org.apache.commons.io.FileUtils import org.bouncycastle.util.encoders.Hex -import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} +import org.enso.runner.common.ProfilingConfig +import org.enso.languageserver.boot.StartupConfig import org.enso.languageserver.data._ import org.enso.logger.ReportLogsOnFailure import org.enso.polyglot.runtime.Runtime.Api diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VcsManagerTest.scala b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VcsManagerTest.scala index 8ce97c2e66..102ebed8e1 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VcsManagerTest.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/websocket/json/VcsManagerTest.scala @@ -7,7 +7,8 @@ import org.eclipse.jgit.api.{Git => JGit} import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.revwalk.RevCommit import org.eclipse.jgit.storage.file.FileRepositoryBuilder -import org.enso.languageserver.boot.{ProfilingConfig, StartupConfig} +import org.enso.runner.common.ProfilingConfig +import org.enso.languageserver.boot.StartupConfig import org.enso.languageserver.data._ import org.enso.languageserver.vcsmanager.VcsApi import org.enso.logger.ReportLogsOnFailure diff --git a/engine/runner-common/src/main/java/org/enso/runner/common/LanguageServerApi.java b/engine/runner-common/src/main/java/org/enso/runner/common/LanguageServerApi.java new file mode 100644 index 0000000000..4dcfc49ec3 --- /dev/null +++ b/engine/runner-common/src/main/java/org/enso/runner/common/LanguageServerApi.java @@ -0,0 +1,29 @@ +package org.enso.runner.common; + +import java.util.ServiceLoader; +import org.apache.commons.cli.CommandLine; +import org.slf4j.event.Level; + +public abstract class LanguageServerApi { + public static final String DAEMONIZE_OPTION = "daemon"; + public static final String ROOT_ID_OPTION = "root-id"; + public static final String ROOT_PATH_OPTION = "path"; + public static final String INTERFACE_OPTION = "interface"; + public static final String RPC_PORT_OPTION = "rpc-port"; + public static final String DATA_PORT_OPTION = "data-port"; + public static final String SECURE_RPC_PORT_OPTION = "secure-rpc-port"; + public static final String SECURE_DATA_PORT_OPTION = "secure-data-port"; + public static final String SKIP_GRAALVM_UPDATER = "skip-graalvm-updater"; + + public static void launchLanguageServer(CommandLine line, ProfilingConfig config, Level logLevel) + throws WrongOption { + var it = + ServiceLoader.load(LanguageServerApi.class, LanguageServerApi.class.getClassLoader()) + .iterator(); + var impl = it.next(); + impl.runLanguageServer(line, config, logLevel); + } + + protected abstract void runLanguageServer( + CommandLine line, ProfilingConfig config, Level logLevel) throws WrongOption; +} diff --git a/engine/runner-common/src/main/java/org/enso/runner/common/WrongOption.java b/engine/runner-common/src/main/java/org/enso/runner/common/WrongOption.java new file mode 100644 index 0000000000..d53b2c84b6 --- /dev/null +++ b/engine/runner-common/src/main/java/org/enso/runner/common/WrongOption.java @@ -0,0 +1,7 @@ +package org.enso.runner.common; + +public final class WrongOption extends Exception { + public WrongOption(String msg) { + super(msg); + } +} diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/libraries/CompilerBasedDependencyExtractor.scala b/engine/runner-common/src/main/scala/org/enso/runner/common/CompilerBasedDependencyExtractor.scala similarity index 98% rename from engine/language-server/src/main/scala/org/enso/languageserver/libraries/CompilerBasedDependencyExtractor.scala rename to engine/runner-common/src/main/scala/org/enso/runner/common/CompilerBasedDependencyExtractor.scala index 54bbbdd0a6..f051948660 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/libraries/CompilerBasedDependencyExtractor.scala +++ b/engine/runner-common/src/main/scala/org/enso/runner/common/CompilerBasedDependencyExtractor.scala @@ -1,4 +1,4 @@ -package org.enso.languageserver.libraries +package org.enso.runner.common import org.enso.editions.LibraryName import org.enso.libraryupload.DependencyExtractor diff --git a/engine/language-server/src/main/scala/org/enso/languageserver/boot/ProfilingConfig.scala b/engine/runner-common/src/main/scala/org/enso/runner/common/ProfilingConfig.scala similarity index 97% rename from engine/language-server/src/main/scala/org/enso/languageserver/boot/ProfilingConfig.scala rename to engine/runner-common/src/main/scala/org/enso/runner/common/ProfilingConfig.scala index e93232da8e..1c4bf05789 100644 --- a/engine/language-server/src/main/scala/org/enso/languageserver/boot/ProfilingConfig.scala +++ b/engine/runner-common/src/main/scala/org/enso/runner/common/ProfilingConfig.scala @@ -1,4 +1,4 @@ -package org.enso.languageserver.boot +package org.enso.runner.common import org.apache.commons.io.FilenameUtils diff --git a/engine/runner/src/main/java/org/enso/runner/Main.java b/engine/runner/src/main/java/org/enso/runner/Main.java index ff0b1aa621..47895e691c 100644 --- a/engine/runner/src/main/java/org/enso/runner/Main.java +++ b/engine/runner/src/main/java/org/enso/runner/Main.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; @@ -28,9 +27,6 @@ import org.enso.common.LanguageInfo; import org.enso.distribution.DistributionManager; import org.enso.distribution.Environment; import org.enso.editions.DefaultEdition; -import org.enso.languageserver.boot.LanguageServerConfig; -import org.enso.languageserver.boot.ProfilingConfig; -import org.enso.languageserver.boot.StartupConfig; import org.enso.libraryupload.LibraryUploader.UploadFailedError; import org.enso.pkg.Contact; import org.enso.pkg.PackageManager; @@ -40,6 +36,9 @@ import org.enso.polyglot.Module; import org.enso.polyglot.PolyglotContext; import org.enso.profiling.sampler.NoopSampler; import org.enso.profiling.sampler.OutputStreamSampler; +import org.enso.runner.common.LanguageServerApi; +import org.enso.runner.common.ProfilingConfig; +import org.enso.runner.common.WrongOption; import org.enso.version.VersionDescription; import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.PolyglotException.StackFrame; @@ -71,14 +70,6 @@ public final class Main { private static final String PROFILING_PATH = "profiling-path"; private static final String PROFILING_TIME = "profiling-time"; private static final String LANGUAGE_SERVER_OPTION = "server"; - private static final String DAEMONIZE_OPTION = "daemon"; - private static final String INTERFACE_OPTION = "interface"; - private static final String RPC_PORT_OPTION = "rpc-port"; - private static final String DATA_PORT_OPTION = "data-port"; - private static final String SECURE_RPC_PORT_OPTION = "secure-rpc-port"; - private static final String SECURE_DATA_PORT_OPTION = "secure-data-port"; - private static final String ROOT_ID_OPTION = "root-id"; - private static final String ROOT_PATH_OPTION = "path"; private static final String IN_PROJECT_OPTION = "in-project"; private static final String VERSION_OPTION = "version"; private static final String JSON_OPTION = "json"; @@ -98,7 +89,6 @@ public final class Main { private static final String HIDE_PROGRESS = "hide-progress"; private static final String AUTH_TOKEN = "auth-token"; private static final String AUTO_PARALLELISM_OPTION = "with-auto-parallelism"; - private static final String SKIP_GRAALVM_UPDATER = "skip-graalvm-updater"; private static final String EXECUTION_ENVIRONMENT_OPTION = "execution-environment"; private static final String WARNINGS_LIMIT = "warnings-limit"; @@ -237,10 +227,13 @@ public final class Main { .desc("The duration in seconds limiting the profiling time.") .build(); var deamonizeOption = - cliOptionBuilder().longOpt(DAEMONIZE_OPTION).desc("Daemonize Language Server").build(); + cliOptionBuilder() + .longOpt(LanguageServerApi.DAEMONIZE_OPTION) + .desc("Daemonize Language Server") + .build(); var interfaceOption = cliOptionBuilder() - .longOpt(INTERFACE_OPTION) + .longOpt(LanguageServerApi.INTERFACE_OPTION) .hasArg(true) .numberOfArgs(1) .argName("interface") @@ -248,7 +241,7 @@ public final class Main { .build(); var rpcPortOption = cliOptionBuilder() - .longOpt(RPC_PORT_OPTION) + .longOpt(LanguageServerApi.RPC_PORT_OPTION) .hasArg(true) .numberOfArgs(1) .argName("rpc-port") @@ -256,7 +249,7 @@ public final class Main { .build(); var secureRpcPortOption = cliOptionBuilder() - .longOpt(SECURE_RPC_PORT_OPTION) + .longOpt(LanguageServerApi.SECURE_RPC_PORT_OPTION) .hasArg(true) .numberOfArgs(1) .argName("rpc-port") @@ -264,7 +257,7 @@ public final class Main { .build(); var dataPortOption = cliOptionBuilder() - .longOpt(DATA_PORT_OPTION) + .longOpt(LanguageServerApi.DATA_PORT_OPTION) .hasArg(true) .numberOfArgs(1) .argName("data-port") @@ -272,7 +265,7 @@ public final class Main { .build(); var secureDataPortOption = cliOptionBuilder() - .longOpt(SECURE_DATA_PORT_OPTION) + .longOpt(LanguageServerApi.SECURE_DATA_PORT_OPTION) .hasArg(true) .numberOfArgs(1) .argName("data-port") @@ -283,7 +276,7 @@ public final class Main { .hasArg(true) .numberOfArgs(1) .argName("uuid") - .longOpt(ROOT_ID_OPTION) + .longOpt(LanguageServerApi.ROOT_ID_OPTION) .desc("Content root id.") .build(); var pathOption = @@ -291,7 +284,7 @@ public final class Main { .hasArg(true) .numberOfArgs(1) .argName("path") - .longOpt(ROOT_PATH_OPTION) + .longOpt(LanguageServerApi.ROOT_PATH_OPTION) .desc("Path to the content root.") .build(); var inProjectOption = @@ -423,7 +416,7 @@ public final class Main { var skipGraalVMUpdater = cliOptionBuilder() - .longOpt(SKIP_GRAALVM_UPDATER) + .longOpt(LanguageServerApi.SKIP_GRAALVM_UPDATER) .desc("Skips GraalVM and its components setup during bootstrapping.") .build(); @@ -1173,84 +1166,6 @@ public final class Main { } } - /** - * Handles `--server` CLI option - * - * @param line a CLI line - * @param logLevel log level to set for the engine runtime - */ - private void runLanguageServer(CommandLine line, Level logLevel) { - try { - var config = parseServerOptions(line); - LanguageServerApp.run(config, logLevel, line.hasOption(Main.DAEMONIZE_OPTION)); - throw exitSuccess(); - } catch (WrongOption e) { - System.err.println(e.getMessage()); - throw exitFail(); - } - } - - private static LanguageServerConfig parseServerOptions(CommandLine line) throws WrongOption { - UUID rootId; - try { - var id = line.getOptionValue(ROOT_ID_OPTION); - if (id == null) { - throw new WrongOption("Root id must be provided"); - } - rootId = UUID.fromString(id); - } catch (IllegalArgumentException e) { - throw new WrongOption("Root must be UUID"); - } - var rootPath = line.getOptionValue(ROOT_PATH_OPTION); - if (rootPath == null) { - throw new WrongOption("Root path must be provided"); - } - var interfac = line.getOptionValue(INTERFACE_OPTION, "127.0.0.1"); - int rpcPort; - try { - rpcPort = Integer.parseInt(line.getOptionValue(RPC_PORT_OPTION, "8080")); - } catch (NumberFormatException e) { - throw new WrongOption("Port must be integer"); - } - int dataPort; - try { - dataPort = Integer.parseInt(line.getOptionValue(DATA_PORT_OPTION, "8081")); - } catch (NumberFormatException e) { - throw new WrongOption("Port must be integer"); - } - Integer secureRpcPort; - try { - var port = line.getOptionValue(SECURE_RPC_PORT_OPTION); - secureRpcPort = port == null ? null : Integer.valueOf(port); - } catch (NumberFormatException e) { - throw new WrongOption("Port must be integer"); - } - Integer secureDataPort; - try { - var port = line.getOptionValue(SECURE_DATA_PORT_OPTION); - secureDataPort = port == null ? null : Integer.valueOf(port); - } catch (NumberFormatException e) { - throw new WrongOption("Port must be integer"); - } - var profilingConfig = parseProfilingConfig(line); - var graalVMUpdater = line.hasOption(SKIP_GRAALVM_UPDATER); - - var config = - new LanguageServerConfig( - interfac, - rpcPort, - scala.Option.apply(secureRpcPort), - dataPort, - scala.Option.apply(secureDataPort), - rootId, - rootPath, - profilingConfig, - new StartupConfig(graalVMUpdater), - "language-server", - ExecutionContext.global()); - return config; - } - private static ProfilingConfig parseProfilingConfig(CommandLine line) throws WrongOption { Path profilingPath = null; try { @@ -1293,7 +1208,7 @@ public final class Main { } @SuppressWarnings("unchecked") - private static final scala.collection.immutable.List nil() { + private static scala.collection.immutable.List nil() { return (scala.collection.immutable.List) scala.collection.immutable.Nil$.MODULE$; } @@ -1425,7 +1340,14 @@ public final class Main { private void launch(Options options, CommandLine line, Level logLevel, boolean logMasking) { if (line.hasOption(LANGUAGE_SERVER_OPTION)) { - runLanguageServer(line, logLevel); + try { + var conf = parseProfilingConfig(line); + LanguageServerApi.launchLanguageServer(line, conf, logLevel); + throw exitSuccess(); + } catch (WrongOption e) { + System.err.println(e.getMessage()); + throw exitFail(); + } } else { try { var conf = parseProfilingConfig(line); @@ -1451,10 +1373,4 @@ public final class Main { protected String getLanguageId() { return LanguageInfo.ID; } - - private static final class WrongOption extends Exception { - WrongOption(String msg) { - super(msg); - } - } } diff --git a/engine/runner/src/main/scala/org/enso/runner/DependencyPreinstaller.scala b/engine/runner/src/main/scala/org/enso/runner/DependencyPreinstaller.scala index f42b2c5413..a26ebc2323 100644 --- a/engine/runner/src/main/scala/org/enso/runner/DependencyPreinstaller.scala +++ b/engine/runner/src/main/scala/org/enso/runner/DependencyPreinstaller.scala @@ -13,7 +13,7 @@ import org.enso.distribution.locking.{ import org.enso.distribution.{DistributionManager, Environment, LanguageHome} import org.enso.editions.updater.EditionManager import org.enso.editions.{DefaultEdition, EditionResolver} -import org.enso.languageserver.libraries.CompilerBasedDependencyExtractor +import org.enso.runner.common.CompilerBasedDependencyExtractor import org.enso.librarymanager.dependencies.DependencyResolver import org.enso.librarymanager.{DefaultLibraryProvider, LibraryResolver} import org.enso.pkg.PackageManager diff --git a/engine/runner/src/main/scala/org/enso/runner/ProjectUploader.scala b/engine/runner/src/main/scala/org/enso/runner/ProjectUploader.scala index 28ad2a6709..7d165c9e66 100644 --- a/engine/runner/src/main/scala/org/enso/runner/ProjectUploader.scala +++ b/engine/runner/src/main/scala/org/enso/runner/ProjectUploader.scala @@ -3,7 +3,7 @@ package org.enso.runner import com.typesafe.scalalogging.Logger import org.enso.cli.ProgressBar import org.enso.cli.task.{ProgressReporter, TaskProgress} -import org.enso.languageserver.libraries.CompilerBasedDependencyExtractor +import org.enso.runner.common.CompilerBasedDependencyExtractor import org.enso.libraryupload.{auth, LibraryUploader} import org.enso.pkg.PackageManager import org.slf4j.event.Level diff --git a/engine/runner/src/test/java/org/enso/runner/EngineRunnerDependenciesTest.java b/engine/runner/src/test/java/org/enso/runner/EngineRunnerDependenciesTest.java new file mode 100644 index 0000000000..74c8b0f75d --- /dev/null +++ b/engine/runner/src/test/java/org/enso/runner/EngineRunnerDependenciesTest.java @@ -0,0 +1,45 @@ +package org.enso.runner; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import org.apache.commons.cli.CommandLine; +import org.enso.runner.common.LanguageServerApi; +import org.enso.runner.common.ProfilingConfig; +import org.enso.runner.common.WrongOption; +import org.junit.Ignore; +import org.junit.Test; +import scala.Option; + +public class EngineRunnerDependenciesTest { + + public EngineRunnerDependenciesTest() {} + + @Test + // ignored for now as engine-runner still has "Runtime" dependency on language-server and that one + // appears in test classpath - remove once language-server is packaged as its own JAR file + @Ignore + public void unableToLoadClassFromLanguageServerProject() { + try { + var b = new CommandLine.Builder(); + b.addArg("server"); + var line = b.build(); + var prof = new ProfilingConfig(Option.empty(), Option.empty()); + LanguageServerApi.launchLanguageServer(line, prof, null); + fail( + "should generate a WrongOption error as support for --server option is missing on" + + " classpath"); + } catch (WrongOption ex) { + // OK + } + } + + @Test + public void ableToLoadRClassFromEngineRunnerCommonProject() throws ClassNotFoundException { + var c = Class.forName("org.enso.runner.common.LanguageServerApi"); + assertNotNull( + "Should be able to load class from engine-runner-common project (obviously as we have" + + " compile time dependency)", + c); + } +} diff --git a/project/NativeImage.scala b/project/NativeImage.scala index e19fad98d9..367c01e844 100644 --- a/project/NativeImage.scala +++ b/project/NativeImage.scala @@ -273,7 +273,7 @@ object NativeImage { val retCode = process.!(processLogger) val targetFile = artifactFile(targetDir, name, true) if (retCode != 0 || !targetFile.exists()) { - log.error("Native Image build of $targetFile failed, with output: ") + log.error(s"Native Image build of $targetFile failed, with output: ") println(sb.toString()) throw new RuntimeException("Native Image build failed") } @@ -317,7 +317,7 @@ object NativeImage { Tracked.diffInputs(store, FileInfo.hash)(filesSet) { sourcesDiff: ChangeReport[File] => if (sourcesDiff.modified.nonEmpty) - rebuild(s"Native Image is not up to date") + rebuild("Native Image is not up to date") else if (!artifactFile(targetDir, name).exists()) rebuild("Native Image does not exist") else diff --git a/tools/legal-review/engine/report-state b/tools/legal-review/engine/report-state index 1d4993e9ac..08d8a9b6a7 100644 --- a/tools/legal-review/engine/report-state +++ b/tools/legal-review/engine/report-state @@ -1,3 +1,3 @@ -8DE3C509911C2AB8D430D76BDB6FD401A8262BC700DA927E97A6CC9055B331C9 +CEACB200CB0700395F9105E8F16462D5DCDAC671A85BC06C502A92FCFE9EDB3D 1CCB55F023131497A0E6A16BB5B2D63E5D842572D8638017816EF1D5474B0169 0