Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Take into account interactively picked options when caching binaries #1701

Merged
Merged
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
3 changes: 2 additions & 1 deletion modules/build/src/main/scala/scala/build/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ object Build {
def dependencyClassPath: Seq[os.Path] = sources.resourceDirs ++ artifacts.classPath
def fullClassPath: Seq[os.Path] = Seq(output) ++ dependencyClassPath
def foundMainClasses(): Seq[String] =
MainClass.find(output) ++ options.classPathOptions.extraClassPath.flatMap(MainClass.find)
MainClass.find(output).sorted ++
options.classPathOptions.extraClassPath.flatMap(MainClass.find).sorted
def retainedMainClass(
mainClasses: Seq[String],
commandString: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,9 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
Nil
val pythonCliOptions = pythonLdFlags.flatMap(f => Seq("--linking-option", f)).toList

val allCliOptions = pythonCliOptions ++ cliOptions
val allCliOptions = pythonCliOptions ++
cliOptions ++
Seq("--main", mainClass)

val nativeWorkDir = build.inputs.nativeWorkDir
os.makeDir.all(nativeWorkDir)
Expand All @@ -1007,9 +1009,7 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
"--outpath",
dest.toString(),
"--workdir",
nativeWorkDir.toString(),
"--main",
mainClass
nativeWorkDir.toString()
) ++ classpath

val scalaNativeCli = build.artifacts.scalaOpt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,11 @@ final class SeveralMainClassesFoundError(
commandString: String,
positions: Seq[Position]
) extends MainClassError(
{
val sortedMainClasses = mainClasses.sorted
val mainClassesString = sortedMainClasses.mkString(", ")
s"""Found several main classes: $mainClassesString
|${sortedMainClasses.headOption.map(mc =>
s"""You can run one of them by passing it with the --main-class option, e.g.
| ${Console.BOLD}$commandString --main-class $mc${Console.RESET}
|""".stripMargin
).getOrElse("")}
|You can pick the main class interactively by passing the --interactive option.
| ${Console.BOLD}$commandString --interactive${Console.RESET}""".stripMargin
},
s"""Found several main classes: ${mainClasses.mkString(", ")}
|You can run one of them by passing it with the --main-class option, e.g.
| ${Console.BOLD}$commandString --main-class ${mainClasses.head}${Console.RESET}
|
|You can pick the main class interactively by passing the --interactive option.
| ${Console.BOLD}$commandString --interactive${Console.RESET}""".stripMargin,
positions = positions
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package scala.cli.integration
import com.eed3si9n.expecty.Expecty.expect

import scala.cli.integration.TestUtil.removeAnsiColors
import scala.util.Properties

trait RunScalaNativeTestDefinitions { _: RunTestDefinitions =>
def simpleNativeTests(): Unit = {
Expand Down Expand Up @@ -234,4 +235,42 @@ trait RunScalaNativeTestDefinitions { _: RunTestDefinitions =>
expect(lines.exists(_.contains("Scala Native options")))
expect(!lines.exists(_.contains("Scala.js options")))
}

test("Take into account interactive main class when caching binaries") {
val inputs = TestInputs(
os.rel / "Main1.scala" ->
"""package foo
|
|object Main1 {
| def main(args: Array[String]): Unit =
| println("Hello from Main1")
|}
|""".stripMargin,
os.rel / "Main2.scala" ->
"""package foo
|
|object Main2 {
| def main(args: Array[String]): Unit =
| println("Hello from Main2")
|}
|""".stripMargin
)
inputs.fromRoot { root =>
val configDir = root / "config"
os.makeDir.all(configDir)
if (!Properties.isWin)
os.perms.set(configDir, "rwx------")
val configEnv = Map("SCALA_CLI_CONFIG" -> (configDir / "config.json").toString)
os.proc(TestUtil.cli, "config", "interactive", "true")
.call(cwd = root, env = configEnv)
val output1 = os.proc(TestUtil.cli, "run", "--native", ".")
.call(cwd = root, env = configEnv ++ Seq("SCALA_CLI_INTERACTIVE_INPUTS" -> "foo.Main1"))
.out.lines().last
expect(output1 == "Hello from Main1")
val output2 = os.proc(TestUtil.cli, "run", "--native", ".")
.call(cwd = root, env = configEnv ++ Seq("SCALA_CLI_INTERACTIVE_INPUTS" -> "foo.Main2"))
.out.lines().last
expect(output2 == "Hello from Main2")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package scala.build.interactive

import scala.io.StdIn.readLine
import scala.io.StdIn

sealed abstract class Interactive extends Product with Serializable {
def confirmOperation(msg: String): Option[Boolean] = None
Expand All @@ -9,6 +9,25 @@ sealed abstract class Interactive extends Product with Serializable {

object Interactive {

private var interactiveInputsOpt =
Option(System.getenv("SCALA_CLI_INTERACTIVE_INPUTS"))
.map(_.linesIterator.toList)

private def readLine(): String =
interactiveInputsOpt match {
case None =>
StdIn.readLine()
case Some(interactiveInputs) =>
synchronized {
interactiveInputs match {
case Nil => ""
case h :: t =>
interactiveInputsOpt = Some(t)
h
}
}
}

case object InteractiveNop extends Interactive

case object InteractiveAsk extends Interactive {
Expand All @@ -17,7 +36,7 @@ object Interactive {
def msg: String
def action: Option[V]
final def run: Option[V] =
if (coursier.paths.Util.useAnsiOutput())
if (interactiveInputsOpt.nonEmpty || coursier.paths.Util.useAnsiOutput())
action
else None
}
Expand All @@ -42,30 +61,31 @@ object Interactive {
options.zipWithIndex.foreach {
case (option, index) => System.err.println(s"[$index] $option")
}
val response = readLine()
val inputIndexOpt = parseIndexInput(response, options.length - 1)
inputIndexOpt.map(options(_))
val response = readLine()
parseIndexInput(response, options.length - 1)
}

private def parseIndexInput(input: String, range: Int): Option[Int] = {
val indexOpt = input.toIntOption
indexOpt match {
private def parseIndexInput(input: String, range: Int): Option[String] =
input.toIntOption match {
case Some(index) =>
val isInRange = index <= range && index >= 0
if (isInRange) Some(index)
if (isInRange) Some(options(index))
else {
System.err.println(
s"The input index number is invalid, integer value from 0 to $range is expected."
)
None
}
case _ =>
System.err.println(
s"Unable to parse input: integer value from 0 to $range is expected."
)
None
case None =>
if (options.contains(input))
Some(input)
else {
System.err.println(
s"Unable to parse input: integer value from 0 to $range is expected."
)
None
}
}
}
}

override def confirmOperation(msg: String): Option[Boolean] = ConfirmOperation(msg).run
Expand Down