Return Engine Version Used in Opened Project (#1454)

add `engineVersion` field with the required Enso version
This commit is contained in:
Dmitry Bushev 2021-02-09 13:55:32 +03:00 committed by GitHub
parent 5e309bddcb
commit 379d17fe3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 149 additions and 31 deletions

View File

@ -83,9 +83,26 @@ This type represents information about a project.
```typescript
interface ProjectMetadata {
/**
* The name of the project.
*/
name: String;
/**
* The project id.
*/
id: UUID;
lastOpened: UTCDateTime;
/**
* Enso Engine version to use for the project, represented by a semver version
* string.
*/
engineVersion: String;
/**
* The last opened datetime.
*/
lastOpened?: UTCDateTime;
}
```
@ -176,7 +193,20 @@ interface ProjectOpenRequest {
```typescript
interface ProjectOpenResult {
/**
* The version of the started language server represented by a semver version
* string.
*/
engineVersion: String;
/**
* The endpoint used for JSON-RPC protocol.
*/
languageServerJsonAddress: IPWithSocket;
/**
* The endpoint used for binary protocol.
*/
languageServerBinaryAddress: IPWithSocket;
}
```
@ -269,6 +299,8 @@ interface ProjectListResponse {
- [`ProjectDataStoreError`](#projectdatastoreerror) to signal problems with
underlying data store.
- [`GlobalConfigurationAccessError`](#globalconfigurationaccesserror) to signal
that the global configuration file could not be accessed or parsed.
### `project/create`

View File

@ -1,6 +1,6 @@
package org.enso.projectmanager.control.core
object syntax {
object syntax extends LowPriorityApplicativeImplicits {
/** Implicit conversion to [[CovariantFlatMapOps]]
*
@ -11,6 +11,10 @@ object syntax {
fa: F[E, A]
): CovariantFlatMapOps[F, E, A] = new CovariantFlatMapOps[F, E, A](fa)
}
trait LowPriorityApplicativeImplicits {
/** Implicit conversion to [[ApplicativeOps]].
*/
implicit def toApplicativeOps[F[+_, +_]: Applicative, E, A](
@ -24,4 +28,5 @@ object syntax {
ff: F[E, A => B]
): ApplicativeFunctionOps[F, E, A, B] =
new ApplicativeFunctionOps[F, E, A, B](ff)
}

View File

@ -3,6 +3,6 @@ package org.enso.projectmanager.data
/** Sockets that a language server listens on.
*
* @param jsonSocket a socket used for JSON-RPC protocol
* @param binarySocket a socket used fot binary protocol
* @param binarySocket a socket used for the binary protocol
*/
case class LanguageServerSockets(jsonSocket: Socket, binarySocket: Socket)

View File

@ -3,14 +3,18 @@ package org.enso.projectmanager.data
import java.time.OffsetDateTime
import java.util.UUID
import nl.gn0s1s.bump.SemVer
/** Contains project metadata.
*
* @param name the name of the project
* @param id the project id
* @param engineVersion version of the engine associated with the project
* @param lastOpened the last opened datetime
*/
case class ProjectMetadata(
name: String,
id: UUID,
engineVersion: SemVer,
lastOpened: Option[OffsetDateTime]
)

View File

@ -0,0 +1,13 @@
package org.enso.projectmanager.data
import nl.gn0s1s.bump.SemVer
/** Information about running language server.
*
* @param engineVersion the version of the started language server
* @param sockets the sockets listened by the language server
*/
case class RunningLanguageServerInfo(
engineVersion: SemVer,
sockets: LanguageServerSockets
)

View File

@ -74,6 +74,7 @@ object ProjectManagementApi {
)
case class Result(
engineVersion: SemVer,
languageServerJsonAddress: Socket,
languageServerBinaryAddress: Socket
)

View File

@ -45,15 +45,16 @@ class ProjectOpenHandler[F[+_, +_]: Exec: CovariantFlatMap](
params.missingComponentAction.getOrElse(MissingComponentAction.Fail)
for {
sockets <- projectService.openProject(
server <- projectService.openProject(
progressTracker = self,
clientId = clientId,
projectId = params.projectId,
missingComponentAction = missingComponentAction
)
} yield ProjectOpen.Result(
languageServerJsonAddress = sockets.jsonSocket,
languageServerBinaryAddress = sockets.binarySocket
engineVersion = server.engineVersion,
languageServerJsonAddress = server.sockets.jsonSocket,
languageServerBinaryAddress = server.sockets.binarySocket
)
}

View File

@ -36,6 +36,8 @@ object ProjectServiceFailureMapper {
ComponentRepositoryUnavailable(msg)
case ComponentUninstallationFailure(msg) =>
ComponentUninstallationError(msg)
case GlobalConfigurationAccessFailure(msg) =>
GlobalConfigurationAccessError(msg)
}
/** [[FailureMapper]] instance for [[ProjectServiceFailure]]. */

View File

@ -6,14 +6,18 @@ import akka.actor.ActorRef
import cats.MonadError
import nl.gn0s1s.bump.SemVer
import org.enso.pkg.PackageManager
import org.enso.projectmanager.control.core.CovariantFlatMap
import org.enso.projectmanager.control.core.{
Applicative,
CovariantFlatMap,
Traverse
}
import org.enso.projectmanager.control.core.syntax._
import org.enso.projectmanager.control.effect.syntax._
import org.enso.projectmanager.control.effect.{ErrorChannel, Sync}
import org.enso.projectmanager.data.{
LanguageServerSockets,
MissingComponentAction,
ProjectMetadata
ProjectMetadata,
RunningLanguageServerInfo
}
import org.enso.projectmanager.infrastructure.languageserver.LanguageServerGateway
import org.enso.projectmanager.infrastructure.languageserver.LanguageServerProtocol._
@ -53,7 +57,9 @@ import org.enso.projectmanager.versionmanagement.DistributionConfiguration
* @param clock a clock
* @param gen a random generator
*/
class ProjectService[F[+_, +_]: ErrorChannel: CovariantFlatMap: Sync](
class ProjectService[
F[+_, +_]: Sync: ErrorChannel: CovariantFlatMap: Applicative
](
validator: ProjectValidator[F],
repo: ProjectRepository[F],
projectCreationService: ProjectCreationServiceApi[F],
@ -197,7 +203,7 @@ class ProjectService[F[+_, +_]: ErrorChannel: CovariantFlatMap: Sync](
clientId: UUID,
projectId: UUID,
missingComponentAction: MissingComponentAction
): F[ProjectServiceFailure, LanguageServerSockets] = {
): F[ProjectServiceFailure, RunningLanguageServerInfo] = {
// format: off
for {
_ <- log.debug(s"Opening project $projectId")
@ -233,7 +239,7 @@ class ProjectService[F[+_, +_]: ErrorChannel: CovariantFlatMap: Sync](
clientId: UUID,
project: Project,
missingComponentAction: MissingComponentAction
): F[ProjectServiceFailure, LanguageServerSockets] = for {
): F[ProjectServiceFailure, RunningLanguageServerInfo] = for {
version <- configurationService
.resolveEnsoVersion(project.engineVersion)
.mapError { case ConfigurationFileAccessFailure(message) =>
@ -260,7 +266,7 @@ class ProjectService[F[+_, +_]: ErrorChannel: CovariantFlatMap: Sync](
s"Language server boot failed: ${th.getMessage}"
)
}
} yield sockets
} yield RunningLanguageServerInfo(version, sockets)
/** @inheritdoc */
override def closeProject(
@ -288,14 +294,31 @@ class ProjectService[F[+_, +_]: ErrorChannel: CovariantFlatMap: Sync](
_.sorted(RecentlyUsedProjectsOrdering)
.take(maybeSize.getOrElse(Int.MaxValue))
)
.map(_.map(toProjectMetadata))
.mapError(toServiceFailure)
.flatMap(xs => Traverse[List].traverse(xs)(resolveProjectMetadata))
private def toProjectMetadata(project: Project): ProjectMetadata =
private def resolveProjectMetadata(
project: Project
): F[ProjectServiceFailure, ProjectMetadata] =
configurationService
.resolveEnsoVersion(project.engineVersion)
.mapError { case ConfigurationFileAccessFailure(message) =>
GlobalConfigurationAccessFailure(
s"Could not deduce the default version to use for the project: " +
s"$message"
)
}
.map(toProjectMetadata(_, project))
private def toProjectMetadata(
engineVersion: SemVer,
project: Project
): ProjectMetadata =
ProjectMetadata(
name = project.name,
id = project.id,
lastOpened = project.lastOpened
name = project.name,
id = project.id,
engineVersion = engineVersion,
lastOpened = project.lastOpened
)
private def getUserProject(

View File

@ -5,9 +5,9 @@ import java.util.UUID
import akka.actor.ActorRef
import nl.gn0s1s.bump.SemVer
import org.enso.projectmanager.data.{
LanguageServerSockets,
MissingComponentAction,
ProjectMetadata
ProjectMetadata,
RunningLanguageServerInfo
}
/** A contract for the Project Service.
@ -62,7 +62,7 @@ trait ProjectServiceApi[F[+_, +_]] {
clientId: UUID,
projectId: UUID,
missingComponentAction: MissingComponentAction
): F[ProjectServiceFailure, LanguageServerSockets]
): F[ProjectServiceFailure, RunningLanguageServerInfo]
/** Closes a project. Tries to shut down the Language Server.
*

View File

@ -102,4 +102,9 @@ object ProjectServiceFailure {
*/
case class ComponentRepositoryAccessFailure(msg: String)
extends ProjectServiceFailure
/** Signals a failure in the configuration service. */
case class GlobalConfigurationAccessFailure(msg: String)
extends ProjectServiceFailure
}

View File

@ -321,4 +321,5 @@ class BaseServerSpec extends JsonRpcServerTestKit with BeforeAndAfterAll {
timeout
) shouldEqual json
}
}

View File

@ -7,6 +7,7 @@ import java.util.UUID
import io.circe.literal._
import nl.gn0s1s.bump.SemVer
import org.apache.commons.io.FileUtils
import org.enso.pkg.SemVerJson._
import org.enso.projectmanager.test.Net.tryConnect
import org.enso.projectmanager.{BaseServerSpec, ProjectManagementOps}
import org.enso.testkit.{FlakySpec, RetrySpec}
@ -484,9 +485,24 @@ class ProjectManagementApiSpec
"id":0,
"result": {
"projects": [
{"name": "Baz", "id": $bazId, "lastOpened": null},
{"name": "Bar", "id": $barId, "lastOpened": null},
{"name": "Foo", "id": $fooId, "lastOpened": null}
{
"name": "Baz",
"id": $bazId,
"engineVersion": $engineToInstall,
"lastOpened": null
},
{
"name": "Bar",
"id": $barId,
"engineVersion": $engineToInstall,
"lastOpened": null
},
{
"name": "Foo",
"id": $fooId,
"engineVersion": $engineToInstall,
"lastOpened": null
}
]
}
}
@ -526,9 +542,24 @@ class ProjectManagementApiSpec
"id":0,
"result": {
"projects": [
{"name": "Bar", "id": $barId, "lastOpened": $barOpenTime},
{"name": "Foo", "id": $fooId, "lastOpened": $fooOpenTime},
{"name": "Baz", "id": $bazId, "lastOpened": null}
{
"name": "Bar",
"id": $barId,
"engineVersion": $engineToInstall,
"lastOpened": $barOpenTime
},
{
"name": "Foo",
"id": $fooId,
"engineVersion": $engineToInstall,
"lastOpened": $fooOpenTime
},
{
"name": "Baz",
"id": $bazId,
"engineVersion": $engineToInstall,
"lastOpened": null
}
]
}
}

View File

@ -18,10 +18,10 @@ class ProjectOpenMissingComponentsSpec
with RetrySpec
with ProjectManagementOps
with MissingComponentBehavior {
val ordinaryVersion: SemVer = SemVer(0, 0, 1)
override val engineToInstall: Option[SemVer] = Some(ordinaryVersion)
var ordinaryProject: UUID = _
var brokenProject: UUID = _
val ordinaryVersion: SemVer = SemVer(0, 0, 1)
override val engineToInstall = Some(ordinaryVersion)
var ordinaryProject: UUID = _
var brokenProject: UUID = _
override val deleteProjectsRootAfterEachTest = false
override def beforeAll(): Unit = {