How to access taskkey values to expose them on serverHandlers in sbt


I would like to expose some properties of my build through sbt server. I am particularly interested about the source files, scala options and some java classpath.

I tried something like this:

serverHandlers += {
  val sources = Keys.sources.value

The problem is that serverHandlers is a SettingKey and sources is a TaskKey and sbt does not allow to use a TaskKey in a SettingKey (and the compiler tell me so “A setting cannot depend on a task”).

I experimented with the loadedBuild setting, in which I get all my projects. From the ResolvedProject class I find a list of settings, but I can’t find a way to get the values of those settings. I tried something like resolvedProject.settings.filter{whatever}.map{ setting => setting.key.value } but got a strange compiler error:

[error] ## Exception when compiling 4 sources to /home/florian/dev/sbt-myPlugin/target/scala-2.12/sbt-1.0/classes
[error] java.lang.IllegalArgumentException: Could not find proxy for setting: sbt.internal.util.Init#Setting in List(value setting, value $anonfun, method $anonfun$globalSettings$5, value projects, method $anonfun$globalSettings$4, value globalSettings, object Plugin, package sbt, package whatever, package com, package <root>) (currentOwner= value globalSettings )

I am stuck on this issue and can’t find a way to expose sources, scalacOptions, etc for each project on sbt server. Is it possible to do it? If so, how?


I got some hints from colleagues and used the same solution as this diff:

The idea is:

It’s probably not the best solution, but it’s the only working one I found :man_shrugging:

Thanks for the thread. Does the following summarize the use case?

  1. add some JSON RPC (LSP/BSP) command
  2. upon request, sbt internally runs a task
  3. returns the result as JSON RPC response

Running evaluate task on your own is usually not safe since the task engine is no longer aware of what’s going on, and it often ends up with mysterious could not create directory race condition.

In Guillaume had the idea of sending jsonRpcRespond from a task. We could add support for that.

The use case is:

  1. Receive a JSON RPC request
  2. Reply with values from the build (sources and scalacOptions TaskKeys values)

The way to do it is what you wrote:

  1. add some JSON RPC (LSP/BSP) command
  2. upon request, sbt internally runs a task
  3. returns the result as JSON RPC response

I didn’t saw the full PR you mentioned, but copied most of the solution out of one of the diff posted in this same PR.