Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ class Build(val crossScalaVersion: String)
Deps.scalaJsEnvNodeJs,
Deps.scalaJsLinkerInterface,
Deps.scalaJsTestAdapter,
Deps.scalaJsEnvJsdomNodejs,
Deps.scalametaTrees,
Deps.scalaparse,
Deps.shapeless,
Expand Down Expand Up @@ -248,6 +249,7 @@ class Build(val crossScalaVersion: String)
| def detailedVersion: Option[String] = $detailedVersionValue
|
| def scalaJsVersion = "${Deps.scalaJsLinker.dep.version}"
| def scalajsEnvJsdomNodejsVersion = "${Deps.scalaJsEnvJsdomNodejs.dep.version}"
| def scalaNativeVersion = "${Deps.nativeTools.dep.version}"
|
| def stubsOrganization = "${stubs.pomSettings().organization}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ final case class SimpleScalaCompiler(
args,
logger,
cwd = Some(project.workspace)
)
).waitFor()

res == 0
}
Expand Down
44 changes: 30 additions & 14 deletions modules/build/src/main/scala/scala/build/internal/Runner.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package scala.build.internal

import coursier.jvm.Execve
import org.scalajs.jsenv.{ExternalJSRun, Input, RunConfig}
import org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv
import sbt.testing.{Framework, Status}

import java.io.File
import java.nio.file.{Files, Path, Paths}

import scala.build.EitherCps.{either, value}
import scala.build.Logger
import scala.build.errors.{
Expand All @@ -26,7 +27,7 @@ object Runner {
logger: Logger,
allowExecve: Boolean = false,
cwd: Option[os.Path] = None
): Int = {
): Process = {

import logger.{log, debug}

Expand Down Expand Up @@ -54,7 +55,8 @@ object Runner {
.inheritIO()
for (dir <- cwd)
b.directory(dir.toIO)
b.start().waitFor()
val process = b.start()
process
}
}

Expand All @@ -67,7 +69,7 @@ object Runner {
logger: Logger,
allowExecve: Boolean = false,
cwd: Option[os.Path] = None
): Int = {
): Process = {

val command =
Seq(javaCommand) ++
Expand Down Expand Up @@ -116,7 +118,7 @@ object Runner {
args: Seq[String],
logger: Logger,
allowExecve: Boolean = false
): Int = {
): Process = {

import logger.{log, debug}

Expand All @@ -129,6 +131,12 @@ object Runner {
command.iterator.map(_ + System.lineSeparator()).mkString
)

val envJs = new JSDOMNodeJSEnv(
JSDOMNodeJSEnv.Config()
.withExecutable(command.head)
.withArgs(command.tail.toList)
)

if (allowExecve && Execve.available()) {
debug("execve available")
Execve.execve(
Expand All @@ -138,19 +146,26 @@ object Runner {
)
sys.error("should not happen")
}
else
new ProcessBuilder(command: _*)
.inheritIO()
.start()
.waitFor()
else {
val inputs = Seq(Input.Script(entrypoint.toPath))

val config = RunConfig().withLogger(logger.scalaJsLogger)
val startJs = envJs.start(inputs, config)

val processField =
startJs.getClass.getDeclaredField("org$scalajs$jsenv$ExternalJSRun$$process")
processField.setAccessible(true)
val process = processField.get(startJs).asInstanceOf[Process]
process
}
}

def runNative(
launcher: File,
args: Seq[String],
logger: Logger,
allowExecve: Boolean = false
): Int = {
): Process = {

import logger.{log, debug}

Expand All @@ -171,11 +186,12 @@ object Runner {
)
sys.error("should not happen")
}
else
new ProcessBuilder(command: _*)
else {
val process = new ProcessBuilder(command: _*)
.inheritIO()
.start()
.waitFor()
process
}
}

private def runTests(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,24 @@ final case class ScalaJsOptions(
) {
def platformSuffix: String =
"sjs" + ScalaVersion.jsBinary(finalVersion).getOrElse(finalVersion)
def jsDependencies(scalaVersion: String): Seq[AnyDependency] =
def jsDomDependencies(scalaVersion: String): Seq[AnyDependency] =
if (scalaVersion.startsWith("2."))
Seq(
dep"org.scala-js::scalajs-dom_sjs1:2.1.0",
dep"org.scala-js::scalajs-env-jsdom-nodejs:1.1.0"
)
else
Seq(
dep"org.scala-js:scalajs-dom_sjs1_2.13:2.1.0",
dep"org.scala-js:scalajs-env-jsdom-nodejs_2.13:1.1.0"
)
def jsDependencies(scalaVersion: String): Seq[AnyDependency] = {
if (scalaVersion.startsWith("2."))
Seq(dep"org.scala-js::scalajs-library:$finalVersion")
else
Seq(dep"org.scala-js:scalajs-library_2.13:$finalVersion")
} ++ jsDomDependencies(scalaVersion)

def compilerPlugins(scalaVersion: String): Seq[AnyDependency] =
if (scalaVersion.startsWith("2."))
Seq(dep"org.scala-js:::scalajs-compiler:$finalVersion")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ object Compile extends ScalaCommand[CompileOptions] {

val compilerMaker = options.shared.compilerMaker(threads)

if (options.watch.watch) {
if (options.watch.watchMode) {
val watcher = Build.watch(
inputs,
buildOptions,
Expand Down
6 changes: 3 additions & 3 deletions modules/cli/src/main/scala/scala/cli/commands/Package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object Package extends ScalaCommand[PackageOptions] {

val cross = options.compileCross.cross.getOrElse(false)

if (options.watch.watch) {
if (options.watch.watchMode) {
var expectedModifyEpochSecondOpt = Option.empty[Long]
val watcher = Build.watch(
inputs,
Expand Down Expand Up @@ -436,7 +436,7 @@ object Package extends ScalaCommand[PackageOptions] {
args,
logger,
cwd = Some(build.inputs.workspace)
)
).waitFor()
if (retCode == 0)
libraryJar(build, hasActualManifest = false, contentDirOverride = Some(destDir))
else
Expand Down Expand Up @@ -761,7 +761,7 @@ object Package extends ScalaCommand[PackageOptions] {
"scala.scalanative.cli.ScalaNativeLd",
args,
logger
)
).waitFor()
if (exitCode == 0)
NativeBuilderHelper.updateProjectAndOutputSha(dest, nativeWorkDir, cacheData.projectSha)
else
Expand Down
6 changes: 3 additions & 3 deletions modules/cli/src/main/scala/scala/cli/commands/Repl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@ object Repl extends ScalaCommand[ReplOptions] {

if (inputs.isEmpty) {
val artifacts = initialBuildOptions.artifacts(logger).orExit(logger)
doRunRepl(initialBuildOptions, artifacts, None, allowExit = !options.watch.watch)
if (options.watch.watch) {
doRunRepl(initialBuildOptions, artifacts, None, allowExit = !options.watch.watchMode)
if (options.watch.watchMode) {
// nothing to watch, just wait for Ctrl+C
WatchUtil.printWatchMessage()
WatchUtil.waitForCtrlC()
}
}
else if (options.watch.watch) {
else if (options.watch.watchMode) {
val watcher = Build.watch(
inputs,
initialBuildOptions,
Expand Down
83 changes: 52 additions & 31 deletions modules/cli/src/main/scala/scala/cli/commands/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package scala.cli.commands
import caseapp._
import org.scalajs.linker.interface.StandardConfig

import java.util.concurrent.CompletableFuture

import scala.build.EitherCps.{either, value}
import scala.build.errors.BuildException
import scala.build.internal.{Constants, Runner}
import scala.build.options.Platform
import scala.build.{Build, BuildThreads, Inputs, Logger}
import scala.cli.CurrentParams
import scala.cli.internal.ProcUtil
import scala.util.Properties

object Run extends ScalaCommand[RunOptions] {
Expand Down Expand Up @@ -42,17 +45,37 @@ object Run extends ScalaCommand[RunOptions] {

val compilerMaker = options.shared.compilerMaker(threads)

def maybeRun(build: Build.Successful, allowTerminate: Boolean): Either[BuildException, Unit] =
maybeRunOnce(
def maybeRun(
build: Build.Successful,
allowTerminate: Boolean
): Either[BuildException, (Process, CompletableFuture[_])] = either {
val process = value(maybeRunOnce(
inputs.workspace,
inputs.projectName,
build,
programArgs,
logger,
allowExecve = allowTerminate,
exitOnError = allowTerminate,
jvmRunner = build.options.addRunnerDependency.getOrElse(true)
)
))

val onExitProcess = process.onExit().thenApply { p1 =>
val retCode = p1.exitValue()
if (retCode != 0)
if (allowTerminate)
sys.exit(retCode)
else {
val red = Console.RED
val lightRed = "\u001b[91m"
val reset = Console.RESET
System.err.println(
s"${red}Program exited with return code $lightRed$retCode$red.$reset"
)
}
}

(process, onExitProcess)
}

val cross = options.compileCross.cross.getOrElse(false)
SetupIde.runSafe(
Expand All @@ -64,7 +87,8 @@ object Run extends ScalaCommand[RunOptions] {
if (CommandUtils.shouldCheckUpdate)
Update.checkUpdateSafe(logger)

if (options.watch.watch) {
if (options.watch.watchMode) {
var processOpt = Option.empty[(Process, CompletableFuture[_])]
val watcher = Build.watch(
inputs,
initialBuildOptions,
Expand All @@ -75,10 +99,18 @@ object Run extends ScalaCommand[RunOptions] {
partial = None,
postAction = () => WatchUtil.printWatchMessage()
) { res =>
for ((process, onExitProcess) <- processOpt) {
onExitProcess.cancel(true)
ProcUtil.interruptProcess(process, logger)
}
res.orReport(logger).map(_.main).foreach {
case s: Build.Successful =>
maybeRun(s, allowTerminate = false)
val maybeProcess = maybeRun(s, allowTerminate = false)
.orReport(logger)
if (options.watch.revolver)
processOpt = maybeProcess
else
maybeProcess.map(_._1.waitFor())
case _: Build.Failed =>
System.err.println("Compilation failed")
}
Expand All @@ -100,8 +132,9 @@ object Run extends ScalaCommand[RunOptions] {
.orExit(logger)
builds.main match {
case s: Build.Successful =>
maybeRun(s, allowTerminate = true)
val (process, _) = maybeRun(s, allowTerminate = true)
.orExit(logger)
process.waitFor()
case _: Build.Failed =>
System.err.println("Compilation failed")
sys.exit(1)
Expand All @@ -116,9 +149,8 @@ object Run extends ScalaCommand[RunOptions] {
args: Seq[String],
logger: Logger,
allowExecve: Boolean,
exitOnError: Boolean,
jvmRunner: Boolean
): Either[BuildException, Unit] = either {
): Either[BuildException, Process] = either {

val mainClassOpt = build.options.mainClass.filter(_.nonEmpty) // trim it too?
.orElse {
Expand All @@ -141,8 +173,7 @@ object Run extends ScalaCommand[RunOptions] {
finalMainClass,
finalArgs,
logger,
allowExecve,
exitOnError
allowExecve
)
value(res)
}
Expand All @@ -154,22 +185,23 @@ object Run extends ScalaCommand[RunOptions] {
mainClass: String,
args: Seq[String],
logger: Logger,
allowExecve: Boolean,
exitOnError: Boolean
): Either[BuildException, Boolean] = either {
allowExecve: Boolean
): Either[BuildException, Process] = either {

val retCode = build.options.platform.value match {
val process = build.options.platform.value match {
case Platform.JS =>
val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger)
val res =
withLinkedJs(build, Some(mainClass), addTestInitializer = false, linkerConfig, logger) {
js =>
Runner.runJs(
val process = Runner.runJs(
js.toIO,
args,
logger,
allowExecve = allowExecve
)
process.onExit().thenApply(_ => if (os.exists(js)) os.remove(js))
process
}
value(res)
case Platform.Native =>
Expand Down Expand Up @@ -198,17 +230,7 @@ object Run extends ScalaCommand[RunOptions] {
)
}

if (retCode != 0)
if (exitOnError)
sys.exit(retCode)
else {
val red = Console.RED
val lightRed = "\u001b[91m"
val reset = Console.RESET
System.err.println(s"${red}Program exited with return code $lightRed$retCode$red.$reset")
}

retCode == 0
process
}

def withLinkedJs[T](
Expand All @@ -219,10 +241,9 @@ object Run extends ScalaCommand[RunOptions] {
logger: Logger
)(f: os.Path => T): Either[BuildException, T] = {
val dest = os.temp(prefix = "main", suffix = ".js")
try Package.linkJs(build, dest, mainClassOpt, addTestInitializer, config, logger).map { _ =>
f(dest)
}
finally if (os.exists(dest)) os.remove(dest)
Package.linkJs(build, dest, mainClassOpt, addTestInitializer, config, logger).map { _ =>
f(dest)
}
}

def withNativeLauncher[T](
Expand Down
Loading