From ffc4c230d2e5eca238346c32d1fd55fc86b76ed4 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Sat, 23 Jul 2022 12:57:54 +0200 Subject: [PATCH] Add bloop command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Basically equivalent to the bloop CLI… --- .../blooprifle/internal/Operations.scala | 37 +++++- .../cli/commands/bloop/BloopOptions.scala | 35 ++++++ .../scala/scala/cli/ScalaCliCommands.scala | 3 +- .../scala/cli/commands/bloop/Bloop.scala | 109 ++++++++++++++++++ .../cli/commands/util/SharedOptionsUtil.scala | 2 +- website/docs/reference/cli-options.md | 19 +++ website/docs/reference/commands.md | 11 ++ 7 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 modules/cli-options/src/main/scala/scala/cli/commands/bloop/BloopOptions.scala create mode 100644 modules/cli/src/main/scala/scala/cli/commands/bloop/Bloop.scala diff --git a/modules/bloop-rifle/src/main/scala/scala/build/blooprifle/internal/Operations.scala b/modules/bloop-rifle/src/main/scala/scala/build/blooprifle/internal/Operations.scala index 1948f10f63..7f7a5b8dd4 100644 --- a/modules/bloop-rifle/src/main/scala/scala/build/blooprifle/internal/Operations.scala +++ b/modules/bloop-rifle/src/main/scala/scala/build/blooprifle/internal/Operations.scala @@ -401,15 +401,46 @@ object Operations { out: OutputStream, err: OutputStream, logger: BloopRifleLogger + ): Int = + run( + "ng-stop", + Array.empty, + workingDir, + address, + None, + out, + err, + logger + ) + + def run( + command: String, + args: Array[String], + workingDir: Path, + address: BloopRifleConfig.Address, + inOpt: Option[InputStream], + out: OutputStream, + err: OutputStream, + logger: BloopRifleLogger, + assumeInTty: Boolean = false, + assumeOutTty: Boolean = false, + assumeErrTty: Boolean = false ): Int = { val stop0 = new AtomicBoolean val nailgunClient0 = nailgunClient(address) - val streams = Streams(None, out, err) + val streams = Streams( + inOpt, + out, + err, + inIsATty = if (assumeInTty) 1 else 0, + outIsATty = if (assumeOutTty) 1 else 0, + errIsATty = if (assumeErrTty) 1 else 0 + ) nailgunClient0.run( - "ng-stop", - Array.empty, + command, + args, workingDir, sys.env.toMap, streams, diff --git a/modules/cli-options/src/main/scala/scala/cli/commands/bloop/BloopOptions.scala b/modules/cli-options/src/main/scala/scala/cli/commands/bloop/BloopOptions.scala new file mode 100644 index 0000000000..7a6fc0387e --- /dev/null +++ b/modules/cli-options/src/main/scala/scala/cli/commands/bloop/BloopOptions.scala @@ -0,0 +1,35 @@ +package scala.cli.commands.bloop + +import caseapp._ + +import scala.cli.commands.{CoursierOptions, LoggingOptions, SharedCompilationServerOptions, SharedDirectoriesOptions, SharedJvmOptions} + +// format: off +final case class BloopOptions( + @Recurse + logging: LoggingOptions = LoggingOptions(), + @Recurse + compilationServer: SharedCompilationServerOptions = SharedCompilationServerOptions(), + @Recurse + directories: SharedDirectoriesOptions = SharedDirectoriesOptions(), + @Recurse + jvm: SharedJvmOptions = SharedJvmOptions(), + @Recurse + coursier: CoursierOptions = CoursierOptions(), + + @ExtraName("workingDir") + @ExtraName("dir") + workingDirectory: Option[String] = None +) { + // format: on + + def workDirOpt: Option[os.Path] = + workingDirectory + .filter(_.trim.nonEmpty) + .map(os.Path(_, os.pwd)) +} + +object BloopOptions { + implicit lazy val parser: Parser[BloopOptions] = Parser.derive + implicit lazy val help: Help[BloopOptions] = Help.derive +} diff --git a/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala b/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala index dd21ef7686..3bf5b3b615 100644 --- a/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala +++ b/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala @@ -6,7 +6,7 @@ import caseapp.core.help.{Help, RuntimeCommandsHelp} import java.nio.file.InvalidPathException import scala.cli.commands._ -import scala.cli.commands.bloop.BloopOutput +import scala.cli.commands.bloop.{Bloop, BloopOutput} import scala.cli.commands.config.Config import scala.cli.commands.default.DefaultFile import scala.cli.commands.github.{SecretCreate, SecretList} @@ -29,6 +29,7 @@ class ScalaCliCommands( private def allCommands = Seq[ScalaCommand[_]]( new About(isSipScala = isSipScala), AddPath, + Bloop, BloopExit, BloopOutput, BloopStart, diff --git a/modules/cli/src/main/scala/scala/cli/commands/bloop/Bloop.scala b/modules/cli/src/main/scala/scala/cli/commands/bloop/Bloop.scala new file mode 100644 index 0000000000..773e24147d --- /dev/null +++ b/modules/cli/src/main/scala/scala/cli/commands/bloop/Bloop.scala @@ -0,0 +1,109 @@ +package scala.cli.commands.bloop + +import caseapp.core.RemainingArgs + +import scala.build.Logger +import scala.build.bloop.BloopThreads +import scala.build.blooprifle.{BloopRifle, BloopRifleConfig} +import scala.build.blooprifle.internal.{Constants, Operations} +import scala.build.internal.OsLibc +import scala.cli.CurrentParams +import scala.cli.commands.{ScalaCommand, SharedOptions} +import scala.cli.commands.util.CommonOps._ +import scala.cli.commands.util.SharedCompilationServerOptionsUtil._ +import scala.cli.commands.util.SharedOptionsUtil._ +import scala.concurrent.Await +import scala.concurrent.duration.Duration + +object Bloop extends ScalaCommand[BloopOptions] { + override def hidden = true + override def inSipScala = false + override def stopAtFirstUnrecognized = true + + private def bloopRifleConfig0(opts: BloopOptions): BloopRifleConfig = { + + // FIXME Basically a tweaked copy of SharedOptionsUtil.bloopRifleConfig + // Some in progress BuildOptions / JavaOptions refactoring of mine should allow + // to stop using SharedOptions and BuildOptions here, and deal with JavaOptions + // directly. + + val sharedOptions = SharedOptions( + logging = opts.logging, + compilationServer = opts.compilationServer, + directories = opts.directories, + jvm = opts.jvm, + coursier = opts.coursier + ) + val options = sharedOptions.buildOptions(false, None) + lazy val defaultJvmCmd = + sharedOptions.downloadJvm(OsLibc.baseDefaultJvm(OsLibc.jvmIndexOs, "17"), options) + val javaCmd = opts.compilationServer.bloopJvm + .map(sharedOptions.downloadJvm(_, options)) + .orElse { + for (javaHome <- options.javaHomeLocationOpt()) yield { + val (javaHomeVersion, javaHomeCmd) = OsLibc.javaHomeVersion(javaHome.value) + if (javaHomeVersion >= 17) javaHomeCmd + else defaultJvmCmd + } + } + .getOrElse(defaultJvmCmd) + + opts.compilationServer.bloopRifleConfig( + opts.logging.logger, + sharedOptions.coursierCache, + opts.logging.verbosity, + javaCmd, + opts.directories.directories, + Some(17) + ) + } + + def run(options: BloopOptions, args: RemainingArgs): Unit = { + CurrentParams.verbosity = options.logging.verbosity + + val threads = BloopThreads.create() + val logger = options.logging.logger + val bloopRifleConfig = bloopRifleConfig0(options) + + val isRunning = BloopRifle.check(bloopRifleConfig, logger.bloopRifleLogger) + + if (isRunning) + logger.debug("Found running Bloop server") + else { + logger.debug("No running Bloop server found, starting one") + val f = BloopRifle.startServer( + bloopRifleConfig, + threads.startServerChecks, + logger.bloopRifleLogger, + bloopRifleConfig.retainedBloopVersion.version.raw, + bloopRifleConfig.javaPath + ) + Await.result(f, Duration.Inf) + logger.message("Bloop server started.") + } + + val args0 = args.all + + args0 match { + case Seq() => + // FIXME Give more details? + logger.message("Bloop server is running.") + case Seq(cmd, args @ _*) => + val assumeTty = System.console() != null + val workingDir = options.workDirOpt.getOrElse(os.pwd).toNIO + Operations.run( + command = cmd, + args = args.toArray, + workingDir = workingDir, + address = bloopRifleConfig.address, + inOpt = Some(System.in), + out = System.out, + err = System.err, + logger = logger.bloopRifleLogger, + assumeInTty = assumeTty, + assumeOutTty = assumeTty, + assumeErrTty = assumeTty + ) + } + } +} diff --git a/modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala b/modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala index b3b3bf2c4a..ed7f36026c 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala @@ -220,7 +220,7 @@ object SharedOptionsUtil { ) } - private def downloadJvm(jvmId: String, options: bo.BuildOptions): String = { + def downloadJvm(jvmId: String, options: bo.BuildOptions): String = { implicit val ec = options.finalCache.ec val javaHomeManager = options.javaHomeManager .withMessage(s"Downloading JVM $jvmId") diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index 5e8e9b1f9b..7f175cee7e 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -46,6 +46,18 @@ Run JMH benchmarks Set JMH version +## Bloop options + +Available in commands: +- [`bloop`](./commands.md#bloop) + + + + +#### `--working-directory` + +Aliases: `--working-dir`, `--dir` + ## Bloop start options Available in commands: @@ -94,6 +106,7 @@ Name of BSP ## Compilation server options Available in commands: +- [`bloop`](./commands.md#bloop) - [`bloop exit`](./commands.md#bloop-exit) - [`bloop output`](./commands.md#bloop-output) - [`bloop start`](./commands.md#bloop-start) @@ -248,6 +261,7 @@ Remove an entry from config ## Coursier options Available in commands: +- [`bloop`](./commands.md#bloop) - [`bloop exit`](./commands.md#bloop-exit) - [`bloop start`](./commands.md#bloop-start) - [`bsp`](./commands.md#bsp) @@ -377,6 +391,7 @@ Update all dependency ## Directories options Available in commands: +- [`bloop`](./commands.md#bloop) - [`bloop exit`](./commands.md#bloop-exit) - [`bloop output`](./commands.md#bloop-output) - [`bloop start`](./commands.md#bloop-start) @@ -524,6 +539,7 @@ Pass scalafmt version before running it. This overrides whatever value is config Available in commands: - [`about`](./commands.md#about) - [`add-path`](./commands.md#add-path) +- [`bloop`](./commands.md#bloop) - [`bloop exit`](./commands.md#bloop-exit) - [`bloop output`](./commands.md#bloop-output) - [`bloop start`](./commands.md#bloop-start) @@ -729,6 +745,7 @@ Set Java properties ## Jvm options Available in commands: +- [`bloop`](./commands.md#bloop) - [`bloop start`](./commands.md#bloop-start) - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) @@ -788,6 +805,7 @@ Port for BSP debugging ## Logging options Available in commands: +- [`bloop`](./commands.md#bloop) - [`bloop exit`](./commands.md#bloop-exit) - [`bloop output`](./commands.md#bloop-output) - [`bloop start`](./commands.md#bloop-start) @@ -1888,6 +1906,7 @@ Force update scala-cli if is outdated Available in commands: - [`about`](./commands.md#about) - [`add-path`](./commands.md#add-path) +- [`bloop`](./commands.md#bloop) - [`bloop exit`](./commands.md#bloop-exit) - [`bloop output`](./commands.md#bloop-output) - [`bloop start`](./commands.md#bloop-start) diff --git a/website/docs/reference/commands.md b/website/docs/reference/commands.md index 048730ad0a..5671778e00 100644 --- a/website/docs/reference/commands.md +++ b/website/docs/reference/commands.md @@ -484,6 +484,17 @@ Accepts options: - [add path](./cli-options.md#add-path-options) - [verbosity](./cli-options.md#verbosity-options) +### `bloop` + +Accepts options: +- [bloop](./cli-options.md#bloop-options) +- [compilation server](./cli-options.md#compilation-server-options) +- [coursier](./cli-options.md#coursier-options) +- [directories](./cli-options.md#directories-options) +- [jvm](./cli-options.md#jvm-options) +- [logging](./cli-options.md#logging-options) +- [verbosity](./cli-options.md#verbosity-options) + ### `bloop exit` Accepts options: