Skip to content

Commit

Permalink
Implement and test 'library/preinstall'
Browse files Browse the repository at this point in the history
  • Loading branch information
radeusgd committed Aug 25, 2021
1 parent 38d065c commit 382b813
Show file tree
Hide file tree
Showing 14 changed files with 277 additions and 129 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.enso.languageserver.boot

import akka.actor.ActorSystem
import org.enso.distribution.locking.ThreadSafeFileLockManager
import org.enso.distribution.locking.{
ResourceManager,
ThreadSafeFileLockManager
}
import org.enso.distribution.{DistributionManager, Environment, LanguageHome}
import org.enso.editions.EditionResolver
import org.enso.editions.updater.EditionManager
Expand All @@ -16,6 +19,7 @@ import org.enso.languageserver.io._
import org.enso.languageserver.libraries.{
EditionReferenceResolver,
LibraryConfig,
LibraryInstallerConfig,
LocalLibraryManager,
ProjectSettingsManager
}
Expand Down Expand Up @@ -290,6 +294,7 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
val lockManager = new ThreadSafeFileLockManager(
distributionManager.paths.locks
)
val resourceManager = new ResourceManager(lockManager)

val lockManagerService = system.actorOf(
LockManagerService.props(lockManager),
Expand Down Expand Up @@ -323,7 +328,12 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
editionManager = editionManager,
localLibraryProvider = DefaultLocalLibraryProvider.make(libraryLocations),
publishedLibraryCache =
PublishedLibraryCache.makeReadOnlyCache(libraryLocations)
PublishedLibraryCache.makeReadOnlyCache(libraryLocations),
installerConfig = LibraryInstallerConfig(
distributionManager,
resourceManager,
Some(languageHome)
)
)

val jsonRpcControllerFactory = new JsonConnectionControllerFactory(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.enso.languageserver.libraries
import org.enso.editions.provider.EditionProvider
import org.enso.editions.{DefaultEdition, EditionResolver, Editions}
import org.enso.languageserver.libraries.EditionReference.NamedEdition
import org.enso.pkg.PackageManager
import org.enso.pkg.{Config, PackageManager}

import java.io.File
import scala.util.Try
Expand All @@ -24,14 +24,14 @@ class EditionReferenceResolver(
case EditionReference.NamedEdition(editionName) =>
editionProvider.findEditionForName(editionName).toTry
case EditionReference.CurrentProjectEdition =>
Try {
projectPackage.config.edition.getOrElse {
// TODO [RW] default edition from config (#1864)
DefaultEdition.getDefaultEdition
}
}
getCurrentProjectConfig.map(_.edition.getOrElse {
// TODO [RW] default edition from config (#1864)
DefaultEdition.getDefaultEdition
})
}

def getCurrentProjectConfig: Try[Config] = Try { projectPackage.config }

/** Resolves all edition dependencies of an edition identified by
* [[EditionReference]].
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import org.enso.librarymanager.published.PublishedLibraryCache
* @param editionManager an instance of edition manager
* @param localLibraryProvider an instance of local library provider
* @param publishedLibraryCache an instance of published library cache
* @param installerConfig configuration for the library installer
*/
case class LibraryConfig(
localLibraryManager: ActorRef,
editionReferenceResolver: EditionReferenceResolver,
editionManager: EditionManager,
localLibraryProvider: LocalLibraryProvider,
publishedLibraryCache: PublishedLibraryCache
publishedLibraryCache: PublishedLibraryCache,
installerConfig: LibraryInstallerConfig
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.enso.languageserver.libraries

import org.enso.distribution.{DistributionManager, LanguageHome}
import org.enso.distribution.locking.ResourceManager

/** Gathers configuration needed by the library installer used in the `library/preinstall` endpoint. */
case class LibraryInstallerConfig(
distributionManager: DistributionManager,
resourceManager: ResourceManager,
languageHome: Option[LanguageHome]
)
Original file line number Diff line number Diff line change
@@ -1,56 +1,150 @@
package org.enso.languageserver.libraries.handler

import akka.actor.{Actor, Props}
import akka.actor.{Actor, ActorRef, Props}
import akka.pattern.pipe
import com.typesafe.scalalogging.LazyLogging
import org.enso.cli.task.notifications.ActorProgressNotificationForwarder
import org.enso.jsonrpc.{Request, ResponseError}
import org.enso.cli.task.{ProgressNotification, ProgressReporter}
import org.enso.distribution.ProgressAndLockNotificationForwarder
import org.enso.distribution.locking.LockUserInterface
import org.enso.editions.LibraryName
import org.enso.jsonrpc.{Id, Request, ResponseError, ResponseResult, Unused}
import org.enso.languageserver.filemanager.FileManagerApi.FileSystemError
import org.enso.languageserver.libraries.FakeDownload
import org.enso.languageserver.libraries.LibraryApi._
import org.enso.languageserver.libraries.handler.LibraryPreinstallHandler.{
InstallationError,
InstallerError,
InternalError,
LibraryInstallationComplete
}
import org.enso.languageserver.libraries.{
EditionReference,
EditionReferenceResolver,
LibraryInstallerConfig
}
import org.enso.languageserver.util.UnhandledLogging
import org.enso.librarymanager.ResolvingLibraryProvider.Error
import org.enso.librarymanager.{
DefaultLibraryProvider,
ResolvedLibrary,
ResolvingLibraryProvider
}

import java.util.concurrent.Executors
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try

/** A request handler for the `library/preinstall` endpoint.
*
* It is currently a stub implementation which will be refined later on.
* @param editionReferenceResolver an [[EditionReferenceResolver]] instance
* @param installerConfig configuration for the library installer
*/
class LibraryPreinstallHandler
extends Actor
class LibraryPreinstallHandler(
editionReferenceResolver: EditionReferenceResolver,
installerConfig: LibraryInstallerConfig
) extends Actor
with LazyLogging
with UnhandledLogging {

implicit private val ec: ExecutionContext =
ExecutionContext.fromExecutor(Executors.newCachedThreadPool())

override def receive: Receive = {
case Request(LibraryPreinstall, id, LibraryPreinstall.Params(_, name)) =>
// TODO [RW] actual implementation
val progressReporter =
ActorProgressNotificationForwarder.translateAndForward(
LibraryPreinstall.name,
sender()
)

if (name == "Test") {
FakeDownload.simulateDownload(
"Download Test",
progressReporter,
seconds = 1
)
} else {
FakeDownload.simulateDownload(
"Downloading something...",
progressReporter
)
FakeDownload.simulateDownload(
"Downloading something else...",
progressReporter
)
case Request(
LibraryPreinstall,
id,
LibraryPreinstall.Params(namespace, name)
) =>
val replyTo = sender()
val libraryName = LibraryName(namespace, name)
val notificationForwarder = new ProgressAndLockNotificationForwarder {
override def sendProgressNotification(
notification: ProgressNotification
): Unit =
replyTo ! ActorProgressNotificationForwarder
.translateProgressNotification(LibraryPreinstall.name, notification)
}

val installation = Future {
val result: Either[InstallationError, ResolvedLibrary] = for {
libraryInstaller <- getLibraryProvider(
notificationForwarder
).toEither.left.map(InternalError)
library <- libraryInstaller
.findLibrary(libraryName)
.left
.map(InstallerError)
} yield library
LibraryInstallationComplete(id, replyTo, libraryName, result)
}
installation pipeTo self

case LibraryInstallationComplete(requestId, replyTo, libraryName, result) =>
result match {
case Left(error) =>
val errorMessage = error match {
case InternalError(throwable) =>
FileSystemError(
s"Could not initialize library installer: " +
s"${throwable.getMessage}"
)
case InstallerError(Error.NotResolved(_)) =>
LibraryNotResolved(libraryName)
case InstallerError(Error.RequestedLocalLibraryDoesNotExist) =>
LocalLibraryNotFound(libraryName)
case InstallerError(Error.DownloadFailed(version, reason)) =>
LibraryDownloadError(libraryName, version, reason.getMessage)
}
replyTo ! ResponseError(
Some(requestId),
errorMessage
)
case Right(_) =>
replyTo ! ResponseResult(LibraryPreinstall, requestId, Unused)
}
sender() ! ResponseError(
Some(id),
FileSystemError("Feature not implemented")
)
}

private def getLibraryProvider(
notificationReporter: ProgressReporter with LockUserInterface
): Try[ResolvingLibraryProvider] =
for {
config <- editionReferenceResolver.getCurrentProjectConfig
edition <- editionReferenceResolver.resolveEdition(
EditionReference.CurrentProjectEdition
)
} yield DefaultLibraryProvider.make(
distributionManager = installerConfig.distributionManager,
resourceManager = installerConfig.resourceManager,
lockUserInterface = notificationReporter,
progressReporter = notificationReporter,
languageHome = installerConfig.languageHome,
edition = edition,
preferLocalLibraries = config.preferLocalLibraries
)
}

object LibraryPreinstallHandler {

/** Creates a configuration object to create [[LibraryPreinstallHandler]]. */
def props(): Props = Props(new LibraryPreinstallHandler)
/** Creates a configuration object to create [[LibraryPreinstallHandler]].
*
* @param editionReferenceResolver an [[EditionReferenceResolver]] instance
* @param installerConfig configuration for the library installer
*/
def props(
editionReferenceResolver: EditionReferenceResolver,
installerConfig: LibraryInstallerConfig
): Props = Props(
new LibraryPreinstallHandler(editionReferenceResolver, installerConfig)
)

case class LibraryInstallationComplete(
requestId: Id,
replyTo: ActorRef,
libraryName: LibraryName,
result: Either[InstallationError, ResolvedLibrary]
)

sealed trait InstallationError
case class InternalError(throwable: Throwable) extends InstallationError
case class InstallerError(error: Error) extends InstallationError
}
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,10 @@ class JsonConnectionController(
.props(requestTimeout, libraryConfig.localLibraryManager),
LibraryGetMetadata -> LibraryGetMetadataHandler
.props(requestTimeout, libraryConfig.localLibraryManager),
LibraryPreinstall -> LibraryPreinstallHandler.props(),
LibraryPreinstall -> LibraryPreinstallHandler.props(
libraryConfig.editionReferenceResolver,
libraryConfig.installerConfig
),
LibraryPublish -> LibraryPublishHandler
.props(requestTimeout, libraryConfig.localLibraryManager),
LibrarySetMetadata -> LibrarySetMetadataHandler
Expand Down
Loading

0 comments on commit 382b813

Please sign in to comment.