Skip to content

Commit

Permalink
add suport for hHCR
Browse files Browse the repository at this point in the history
  • Loading branch information
iusildra committed Aug 18, 2023
1 parent 625b4e3 commit a2f5a2a
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 62 deletions.
2 changes: 1 addition & 1 deletion frontend/src/main/scala/bloop/bsp/BloopBspServices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ final class BloopBspServices(
BloopDebuggeeRunner.forTestSuite(projects, testClasses, state, ioScheduler)
})
case bsp.DebugSessionParamsDataKind.ScalaAttachRemote =>
Right(BloopDebuggeeRunner.forAttachRemote(state, ioScheduler, projects))
Right(BloopDebuggeeRunner.forAttachRemote(projects, state, ioScheduler))
case dataKind => Left(Response.invalidRequest(s"Unsupported data kind: $dataKind"))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class BloopDebugToolsResolver(logger: Logger) extends DebugToolsResolver {
}
}

override def resolveStepFilter(scalaVersion: ScalaVersion): Try[ClassLoader] = {
override def resolveUnpickler(scalaVersion: ScalaVersion): Try[ClassLoader] = {
getOrTryUpdate(stepFilterCache, scalaVersion) {
val stepFilterModule = s"${BuildInfo.scala3StepFilterName}_${scalaVersion.binaryVersion}"
val stepFilter = Artifact(BuildInfo.organization, stepFilterModule, BuildInfo.version)
val unpicklerModule = s"${BuildInfo.unpicklerName}_${scalaVersion.binaryVersion}"
val stepFilter = Artifact(BuildInfo.organization, unpicklerModule, BuildInfo.version)
val tastyCore = Artifact("org.scala-lang", "tasty-core_3", scalaVersion.value)
DependencyResolution
.resolveWithErrors(List(stepFilter, tastyCore), logger)
Expand Down
103 changes: 64 additions & 39 deletions frontend/src/main/scala/bloop/dap/BloopDebuggee.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,23 @@ import bloop.testing.DebugLoggingEventHandler
import bloop.testing.TestInternals

import monix.execution.Scheduler
import io.reactivex.Observable
import java.util.concurrent.Semaphore

abstract class BloopDebuggee(
initialState: State,
ioScheduler: Scheduler,
debugeeScalaVersion: Option[String]
debuggeeScalaVersion: Option[String]
) extends Debuggee {

// The version doesn't matter for project without Scala version (Java only)
val scalaVersion = ScalaVersion(debugeeScalaVersion.getOrElse("2.13.8"))
val scalaVersion = ScalaVersion(debuggeeScalaVersion.getOrElse("2.13.8"))

override def run(listener: DebuggeeListener): CancelableFuture[Unit] = {
val debugSessionLogger = new DebuggeeLogger(listener, initialState.logger)

val task = start(initialState.copy(logger = debugSessionLogger), listener)
.map { status =>
if (!status.isOk) throw new Exception(s"debugee failed with ${status.name}")
if (!status.isOk) throw new Exception(s"debuggee failed with ${status.name}")
}
DapCancellableFuture.runAsync(task, ioScheduler)
}
Expand All @@ -51,9 +52,12 @@ private final class MainClassDebugAdapter(
val unmanagedEntries: Seq[UnmanagedEntry],
env: JdkConfig,
initialState: State,
ioScheduler: Scheduler,
scalaVersion: Option[String]
) extends BloopDebuggee(initialState, ioScheduler, scalaVersion) {
ioScheduler: Scheduler
) extends BloopDebuggee(initialState, ioScheduler, project.scalaInstance.map(_.version)) {

val classesToUpdate: Observable[Seq[String]] = project.classObserver
val compileLocks: Semaphore = project.compileLock

val javaRuntime: Option[JavaRuntime] = JavaRuntime(env.javaHome.underlying)
def name: String = s"${getClass.getSimpleName}(${project.name}, ${mainClass.`class`})"
def start(state: State, listener: DebuggeeListener): Task[ExitStatus] = {
Expand All @@ -74,6 +78,11 @@ private final class MainClassDebugAdapter(
)
runState.map(_.status)
}

override def compile(): Unit = {
compileLocks.acquire()
compileLocks.release()
}
}

private final class TestSuiteDebugAdapter(
Expand All @@ -84,9 +93,18 @@ private final class TestSuiteDebugAdapter(
val unmanagedEntries: Seq[UnmanagedEntry],
val javaRuntime: Option[JavaRuntime],
initialState: State,
ioScheduler: Scheduler,
val debugeeScalaVersion: Option[String]
) extends BloopDebuggee(initialState, ioScheduler, debugeeScalaVersion) {
ioScheduler: Scheduler
) extends BloopDebuggee(
initialState,
ioScheduler,
projects.headOption.flatMap(_.scalaInstance).map(_.version)
) {

val classesToUpdate: Observable[Seq[String]] =
projects.map(_.classObserver).fold(Observable.empty[Seq[String]])(_ mergeWith _)
val compileLocks: Seq[Semaphore] = projects.map(_.compileLock)

override def compile(): Unit = ()
override def name: String = {
val projectsStr = projects.map(_.bspUri).mkString("[", ", ", "]")
val selectedTests = testClasses.suites
Expand Down Expand Up @@ -116,21 +134,41 @@ private final class TestSuiteDebugAdapter(
}

private final class AttachRemoteDebugAdapter(
projects: Seq[Project],
val modules: Seq[Module],
val libraries: Seq[Library],
val unmanagedEntries: Seq[UnmanagedEntry],
val javaRuntime: Option[JavaRuntime],
initialState: State,
ioScheduler: Scheduler,
val debugeeScalaVersion: Option[String]
) extends BloopDebuggee(initialState, ioScheduler, debugeeScalaVersion) {
ioScheduler: Scheduler
) extends BloopDebuggee(
initialState,
ioScheduler,
projects.headOption.flatMap(_.scalaInstance).map(_.version)
) {

override def name: String = s"${getClass.getSimpleName}(${initialState.build.origin})"
override def start(state: State, listener: DebuggeeListener): Task[ExitStatus] = Task(
ExitStatus.Ok
)
val classesToUpdate: Observable[Seq[String]] =
projects.map(_.classObserver).fold(Observable.empty[Seq[String]])(_ mergeWith _)
val compileLocks: Seq[Semaphore] = projects.map(_.compileLock)
override def compile(): Unit = ()
}

object BloopDebuggeeRunner {
def getEntries(
project: Project,
state: State
): (Seq[Module], Seq[Library], Seq[UnmanagedEntry]) = {
val dag = state.build.getDagFor(project)
val modules = getModules(dag, state.client)
val libraries = getLibraries(dag)
val unmanagedEntries =
getUnmanagedEntries(project, dag, state.client, modules ++ libraries)
(modules, libraries, unmanagedEntries)
}

def forMainClass(
projects: Seq[Project],
Expand All @@ -143,11 +181,7 @@ object BloopDebuggeeRunner {
case Seq(project) =>
project.platform match {
case jvm: Platform.Jvm =>
val dag = state.build.getDagFor(project)
val modules = getModules(dag, state.client)
val libraries = getLibraries(dag)
val unmanagedEntries =
getUnmanagedEntries(project, dag, state.client, modules ++ libraries)
val (modules, libraries, unmanagedEntries) = getEntries(project, state)
Right(
new MainClassDebugAdapter(
project,
Expand All @@ -157,8 +191,7 @@ object BloopDebuggeeRunner {
unmanagedEntries,
jvm.config,
state,
ioScheduler,
project.scalaInstance.map(_.version)
ioScheduler
)
)
case platform =>
Expand All @@ -178,10 +211,7 @@ object BloopDebuggeeRunner {
case Seq() =>
Left(s"No projects specified for the test suites: [${testClasses.classNames.sorted}]")
case Seq(project) if project.platform.isInstanceOf[Platform.Jvm] =>
val dag = state.build.getDagFor(project)
val modules = getModules(dag, state.client)
val libraries = getLibraries(dag)
val unmanagedEntries = getUnmanagedEntries(project, dag, state.client, modules ++ libraries)
val (modules, libraries, unmanagedEntries) = getEntries(project, state)
val Platform.Jvm(config, _, _, _, _, _) = project.platform
val javaRuntime = JavaRuntime(config.javaHome.underlying)
Right(
Expand All @@ -193,12 +223,11 @@ object BloopDebuggeeRunner {
unmanagedEntries,
javaRuntime,
state,
ioScheduler,
project.scalaInstance.map(_.version)
ioScheduler
)
)

case project :: _ =>
case _ =>
Right(
new TestSuiteDebugAdapter(
projects,
Expand All @@ -208,45 +237,41 @@ object BloopDebuggeeRunner {
Seq.empty,
None,
state,
ioScheduler,
project.scalaInstance.map(_.version)
ioScheduler
)
)

}
}

def forAttachRemote(
projects: Seq[Project],
state: State,
ioScheduler: Scheduler,
projects: Seq[Project]
ioScheduler: Scheduler
): Debuggee = {
projects match {
case Seq(project) if project.platform.isInstanceOf[Platform.Jvm] =>
val dag = state.build.getDagFor(project)
val libraries = getLibraries(dag)
val modules = getModules(dag, state.client)
val unmanagedEntries = getUnmanagedEntries(project, dag, state.client, modules ++ libraries)
val (modules, libraries, unmanagedEntries) = getEntries(project, state)
val Platform.Jvm(config, _, _, _, _, _) = project.platform
val javaRuntime = JavaRuntime(config.javaHome.underlying)
new AttachRemoteDebugAdapter(
Seq(project),
modules,
libraries,
unmanagedEntries,
javaRuntime,
state,
ioScheduler,
project.scalaInstance.map(_.version)
ioScheduler
)
case projects =>
new AttachRemoteDebugAdapter(
projects,
Seq.empty,
Seq.empty,
Seq.empty,
None,
state,
ioScheduler,
projects.headOption.flatMap(_.scalaInstance).map(_.version)
ioScheduler
)
}
}
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/main/scala/bloop/data/Project.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import com.typesafe.config.ConfigSyntax
import scalaz.Cord
import xsbti.compile.ClasspathOptions
import xsbti.compile.CompileOrder
import java.util.concurrent.Semaphore
import io.reactivex.subjects.PublishSubject

final case class Project(
name: String,
Expand Down Expand Up @@ -59,6 +61,10 @@ final case class Project(
origin: Origin
) {

val compileLock = new Semaphore(1)

val classObserver = PublishSubject.create[Seq[String]]()

/** The bsp uri associated with this project. */
val bspUri: Bsp.Uri = Bsp.Uri(ProjectUris.toURI(baseDirectory, name))

Expand Down
20 changes: 14 additions & 6 deletions frontend/src/main/scala/bloop/engine/tasks/CompileTask.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ object CompileTask {
): Task[State] = Task.defer {
import bloop.data.ClientInfo
import bloop.internal.build.BuildInfo

val originUri = state.build.origin
val cwd = originUri.getParent
val topLevelTargets = Dag.directDependencies(List(dag)).mkString(", ")
Expand Down Expand Up @@ -93,6 +94,10 @@ object CompileTask {
"compile.target" -> project.name
)

project.compileLock.acquire()

println("compiling")

bundle.prepareSourcesAndInstance match {
case Left(earlyResultBundle) =>
compileProjectTracer.terminate()
Expand Down Expand Up @@ -190,9 +195,13 @@ object CompileTask {
}

// Populate the last successful result if result was success
result match {
val compileResult = result match {
case s: Compiler.Result.Success =>
val runningTasks = runPostCompilationTasks(s.backgroundTasks)
val updatedClasses = s.products.generatedRelativeClassFilePaths.keySet
.map(_.drop(1).dropRight(6).replaceAll("/", "."))
.toSeq // TODO: returns only changed class files
project.classObserver.onNext(updatedClasses)
val blockingOnRunningTasks = Task
.fromFuture(runningTasks)
.executeOn(ExecutionContext.ioScheduler)
Expand Down Expand Up @@ -221,6 +230,8 @@ object CompileTask {
_: Compiler.Result.GlobalError =>
ResultBundle(result, None, None, CancelableFuture.unit)
}
project.compileLock.release()
compileResult
}
}
}
Expand Down Expand Up @@ -327,12 +338,9 @@ object CompileTask {
runIOTasksInParallel(cleanUpTasksToRunInBackground)

val runningTasksRequiredForCorrectness = Task.sequence {
results.flatMap {
results.collect {
case FinalNormalCompileResult(_, result) =>
val tasksAtEndOfBuildCompilation =
Task.fromFuture(result.runningBackgroundTasks)
List(tasksAtEndOfBuildCompilation)
case _ => Nil
Task.fromFuture(result.runningBackgroundTasks)
}
}

Expand Down
17 changes: 17 additions & 0 deletions frontend/src/test/scala/bloop/dap/DebugAdapterConnection.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import com.microsoft.java.debug.core.protocol.Responses.VariablesResponseBody
import com.microsoft.java.debug.core.protocol.Types.Capabilities
import monix.execution.Cancelable
import monix.execution.Scheduler
import com.microsoft.java.debug.core.protocol.Responses.RedefineClassesResponse
import java.nio.file.Files
import bloop.io.AbsolutePath
import java.nio.file.Path

/**
* Manages a connection with a debug adapter.
Expand Down Expand Up @@ -64,6 +68,8 @@ private[dap] final class DebugAdapterConnection(
def setBreakpoints(
arguments: SetBreakpointArguments
): Task[SetBreakpointsResponseBody] = {
println(s"Source: ${arguments.source.path}")
println(Files.readString(Path.of(arguments.source.path)))
adapter.request(SetBreakpoints, arguments)
}

Expand Down Expand Up @@ -119,6 +125,17 @@ private[dap] final class DebugAdapterConnection(
adapter.request(Attach, arguments)
}

def stepIn(threadId: Long): Task[Unit] = {
val args = new StepInArguments()
args.threadId = threadId
adapter.request(StepIn, args)
}

def redefineClasses(): Task[RedefineClassesResponse] = {
val args = new RedefineClassesArguments()
adapter.request(RedefineClasses, args)
}

def close(): Unit = {
try socket.close()
finally {
Expand Down
Loading

0 comments on commit a2f5a2a

Please sign in to comment.