mirror of
https://github.com/enso-org/enso.git
synced 2024-11-22 22:10:15 +03:00
Add a method for getting component groups without execution context (#7569)
close #7510 Changelog: - add: `runtime/getComponentGroups` request returning the component groups currently available in runtime
This commit is contained in:
parent
d3436fae70
commit
060323e511
@ -182,6 +182,8 @@ transport formats, please look [here](./protocol-architecture).
|
||||
- [`library/getPackage`](#librarygetpackage)
|
||||
- [`library/publish`](#librarypublish)
|
||||
- [`library/preinstall`](#librarypreinstall)
|
||||
- [Runtime Operations](#runtime-operations)
|
||||
- [`runtime/getComponentGroups`](#runtime-getcomponentgroups)
|
||||
- [Errors](#errors-75)
|
||||
- [`Error`](#error)
|
||||
- [`AccessDeniedError`](#accessdeniederror)
|
||||
@ -3888,12 +3890,10 @@ null;
|
||||
Sent from the client to the server to get the list of component groups available
|
||||
in runtime.
|
||||
|
||||
The engine is started with an empty list of libraries loaded. It means that the
|
||||
request should be sent after the first
|
||||
[`executionContext/executionComplete`](#executioncontextexecutioncomplete)
|
||||
notification indicating that all the libraries are loaded, and the component
|
||||
group list is populated. If the request is sent before the first notification,
|
||||
the response may be empty or not contain all available components.
|
||||
#### Deprecated
|
||||
|
||||
The request is deprecated in favor of
|
||||
[`runtime/getComponentGroups`](#runtime-getcomponentgroups).
|
||||
|
||||
- **Type:** Request
|
||||
- **Direction:** Client -> Server
|
||||
@ -5333,6 +5333,43 @@ null;
|
||||
- [`FileSystemError`](#filesystemerror) to signal a generic, unrecoverable
|
||||
file-system error.
|
||||
|
||||
## Runtime Operations
|
||||
|
||||
### `runtime/getComponentGroups`
|
||||
|
||||
Sent from the client to the server to get the list of component groups available
|
||||
in runtime.
|
||||
|
||||
The engine is started with an empty list of libraries loaded. It means that the
|
||||
request should be sent after the first
|
||||
[`executionContext/executionComplete`](#executioncontextexecutioncomplete)
|
||||
notification indicating that all the libraries are loaded, and the component
|
||||
group list is populated. If the request is sent before the first notification,
|
||||
the response may be empty or not contain all available components.
|
||||
|
||||
- **Type:** Request
|
||||
- **Direction:** Client -> Server
|
||||
- **Connection:** Protocol
|
||||
- **Visibility:** Public
|
||||
|
||||
#### Parameters
|
||||
|
||||
```typescript
|
||||
null;
|
||||
```
|
||||
|
||||
#### Result
|
||||
|
||||
```typescript
|
||||
{
|
||||
componentGroups: LibraryComponentGroup[];
|
||||
}
|
||||
```
|
||||
|
||||
#### Errors
|
||||
|
||||
None
|
||||
|
||||
## Errors
|
||||
|
||||
The language server component also has its own set of errors. This section is
|
||||
|
@ -57,6 +57,7 @@ import org.enso.languageserver.requesthandler.visualization.{
|
||||
import org.enso.languageserver.requesthandler.workspace.ProjectInfoHandler
|
||||
import org.enso.languageserver.runtime.ContextRegistryProtocol
|
||||
import org.enso.languageserver.runtime.ExecutionApi._
|
||||
import org.enso.languageserver.runtime.RuntimeApi.RuntimeGetComponentGroups
|
||||
import org.enso.languageserver.runtime.VisualizationApi.{
|
||||
AttachVisualization,
|
||||
DetachVisualization,
|
||||
@ -584,6 +585,10 @@ class JsonConnectionController(
|
||||
RenameSymbol -> RenameSymbolHandler.props(
|
||||
requestTimeout,
|
||||
runtimeConnector
|
||||
),
|
||||
RuntimeGetComponentGroups -> runtime.GetComponentGroupsHandler.props(
|
||||
requestTimeout,
|
||||
runtimeConnector
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import org.enso.languageserver.runtime.VisualizationApi._
|
||||
import org.enso.languageserver.session.SessionApi.InitProtocolConnection
|
||||
import org.enso.languageserver.text.TextApi._
|
||||
import org.enso.languageserver.libraries.LibraryApi._
|
||||
import org.enso.languageserver.runtime.RuntimeApi.RuntimeGetComponentGroups
|
||||
import org.enso.languageserver.vcsmanager.VcsManagerApi._
|
||||
import org.enso.languageserver.workspace.WorkspaceApi.ProjectInfo
|
||||
|
||||
@ -100,6 +101,7 @@ object JsonRpc {
|
||||
.registerRequest(LibraryGetPackage)
|
||||
.registerRequest(LibraryPublish)
|
||||
.registerRequest(LibraryPreinstall)
|
||||
.registerRequest(RuntimeGetComponentGroups)
|
||||
.registerNotification(TaskStarted)
|
||||
.registerNotification(TaskProgressUpdate)
|
||||
.registerNotification(TaskFinished)
|
||||
|
@ -0,0 +1,146 @@
|
||||
package org.enso.languageserver.requesthandler.runtime
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Cancellable, Props}
|
||||
import com.typesafe.scalalogging.LazyLogging
|
||||
import org.enso.editions.LibraryName
|
||||
import org.enso.jsonrpc._
|
||||
import org.enso.languageserver.libraries.{
|
||||
ComponentGroupsResolver,
|
||||
ComponentGroupsValidator,
|
||||
LibraryComponentGroup
|
||||
}
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.runtime.RuntimeApi._
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.pkg.ComponentGroups
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
import scala.collection.immutable.ListMap
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
/** A request handler for `runtime/getComponentGroups` commands.
|
||||
*
|
||||
* @param timeout request timeout
|
||||
* @param runtime a reference to the runtime connector
|
||||
* @param componentGroupsResolver resolves dependencies between the component
|
||||
* groups of different packages
|
||||
* @param componentGroupsValidator validates the component groups
|
||||
*/
|
||||
class GetComponentGroupsHandler(
|
||||
timeout: FiniteDuration,
|
||||
runtime: ActorRef,
|
||||
componentGroupsResolver: ComponentGroupsResolver,
|
||||
componentGroupsValidator: ComponentGroupsValidator
|
||||
) extends Actor
|
||||
with LazyLogging
|
||||
with UnhandledLogging {
|
||||
|
||||
import context.dispatcher
|
||||
|
||||
override def receive: Receive = requestStage
|
||||
|
||||
private def requestStage: Receive = {
|
||||
case Request(
|
||||
RuntimeGetComponentGroups,
|
||||
id,
|
||||
_
|
||||
) =>
|
||||
runtime ! Api.Request(UUID.randomUUID(), Api.GetComponentGroupsRequest())
|
||||
val cancellable =
|
||||
context.system.scheduler.scheduleOnce(timeout, self, RequestTimeout)
|
||||
context.become(responseStage(id, sender(), cancellable))
|
||||
}
|
||||
|
||||
private def responseStage(
|
||||
id: Id,
|
||||
replyTo: ActorRef,
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
logger.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
case Api.Response(_, Api.GetComponentGroupsResponse(componentGroups)) =>
|
||||
replyTo ! ResponseResult(
|
||||
RuntimeGetComponentGroups,
|
||||
id,
|
||||
RuntimeGetComponentGroups.Result(
|
||||
resolveComponentGroups(componentGroups.to(ListMap))
|
||||
)
|
||||
)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
}
|
||||
|
||||
private def resolveComponentGroups(
|
||||
componentGroups: Map[LibraryName, ComponentGroups]
|
||||
): Seq[LibraryComponentGroup] = {
|
||||
val validated = componentGroupsValidator.validate(componentGroups)
|
||||
|
||||
validated.collect { case (_, Left(error)) =>
|
||||
logValidationError(error)
|
||||
}
|
||||
|
||||
val validatedComponents = validated
|
||||
.collect { case (libraryName, Right(componentGroups)) =>
|
||||
libraryName -> componentGroups
|
||||
}
|
||||
componentGroupsResolver.resolveComponentGroups(validatedComponents)
|
||||
}
|
||||
|
||||
private def logValidationError(
|
||||
error: ComponentGroupsValidator.ValidationError
|
||||
): Unit =
|
||||
error match {
|
||||
case ComponentGroupsValidator.ValidationError
|
||||
.InvalidComponentGroups(libraryName, message) =>
|
||||
logger.warn(
|
||||
s"Validation error. Failed to read library [$libraryName] " +
|
||||
s"component groups (reason: $message)."
|
||||
)
|
||||
case ComponentGroupsValidator.ValidationError
|
||||
.DuplicatedComponentGroup(libraryName, moduleReference) =>
|
||||
logger.warn(
|
||||
s"Validation error. Library [$libraryName] defines duplicate " +
|
||||
s"component group [$moduleReference]."
|
||||
)
|
||||
case ComponentGroupsValidator.ValidationError
|
||||
.ComponentGroupExtendsNothing(libraryName, moduleReference) =>
|
||||
logger.warn(
|
||||
s"Validation error. Library [$libraryName] component group " +
|
||||
s"[$moduleReference] extends nothing."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object GetComponentGroupsHandler {
|
||||
|
||||
/** Creates configuration object used to create a
|
||||
* [[GetComponentGroupsHandler]].
|
||||
*
|
||||
* @param timeout request timeout
|
||||
* @param runtime a reference to the runtime connector
|
||||
* @param componentGroupsResolver resolves dependencies between the component
|
||||
* groups of different packages
|
||||
* @param componentGroupsValidator validates the component groups
|
||||
*/
|
||||
def props(
|
||||
timeout: FiniteDuration,
|
||||
runtime: ActorRef,
|
||||
componentGroupsResolver: ComponentGroupsResolver =
|
||||
new ComponentGroupsResolver,
|
||||
componentGroupsValidator: ComponentGroupsValidator =
|
||||
new ComponentGroupsValidator
|
||||
): Props =
|
||||
Props(
|
||||
new GetComponentGroupsHandler(
|
||||
timeout,
|
||||
runtime,
|
||||
componentGroupsResolver,
|
||||
componentGroupsValidator
|
||||
)
|
||||
)
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.enso.languageserver.runtime
|
||||
|
||||
import org.enso.jsonrpc.{HasParams, HasResult, Method, Unused}
|
||||
import org.enso.languageserver.libraries.LibraryComponentGroup
|
||||
|
||||
object RuntimeApi {
|
||||
|
||||
case object RuntimeGetComponentGroups
|
||||
extends Method("runtime/getComponentGroups") {
|
||||
|
||||
case class Result(componentGroups: Seq[LibraryComponentGroup])
|
||||
|
||||
implicit val hasParams: HasParams.Aux[this.type, Unused.type] =
|
||||
new HasParams[this.type] {
|
||||
type Params = Unused.type
|
||||
}
|
||||
implicit val hasResult
|
||||
: HasResult.Aux[this.type, RuntimeGetComponentGroups.Result] =
|
||||
new HasResult[this.type] {
|
||||
type Result = RuntimeGetComponentGroups.Result
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package org.enso.languageserver.websocket.json
|
||||
|
||||
import io.circe.literal._
|
||||
import org.enso.languageserver.runtime.TestComponentGroups
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
|
||||
class RuntimeTest extends BaseServerTest {
|
||||
|
||||
"runtime/getComponentGroups" should {
|
||||
|
||||
"return component groups successfully" in {
|
||||
val client = getInitialisedWsClient()
|
||||
|
||||
// get component groups
|
||||
client.send(
|
||||
json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "runtime/getComponentGroups",
|
||||
"id": 1,
|
||||
"params": null
|
||||
}
|
||||
"""
|
||||
)
|
||||
val requestId =
|
||||
runtimeConnectorProbe.receiveN(1).head match {
|
||||
case Api.Request(requestId, Api.GetComponentGroupsRequest()) =>
|
||||
requestId
|
||||
case msg =>
|
||||
fail(s"Unexpected message: $msg")
|
||||
}
|
||||
|
||||
runtimeConnectorProbe.lastSender ! Api.Response(
|
||||
requestId,
|
||||
Api.GetComponentGroupsResponse(
|
||||
TestComponentGroups.standardBase.toVector
|
||||
)
|
||||
)
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {
|
||||
"componentGroups": [
|
||||
{
|
||||
"library" : "Standard.Base",
|
||||
"name" : "Input",
|
||||
"exports" : [
|
||||
{
|
||||
"name" : "Standard.Base.File.new"
|
||||
},
|
||||
{
|
||||
"name" : "Standard.Database.Connection.Database.connect"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
""")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user