Skip to content

Commit b190866

Browse files
authored
Add more interactive options (#1040)
* Add more interactive options
1 parent dec9916 commit b190866

File tree

15 files changed

+197
-107
lines changed

15 files changed

+197
-107
lines changed

modules/build/src/main/scala/scala/build/Build.scala

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import scala.build.EitherCps.{either, value}
1414
import scala.build.Ops.*
1515
import scala.build.compiler.{ScalaCompiler, ScalaCompilerMaker}
1616
import scala.build.errors.*
17-
import scala.build.interactive.Interactive
1817
import scala.build.internal.{Constants, CustomCodeWrapper, MainClass, Util}
1918
import scala.build.options.*
2019
import scala.build.options.validation.ValidationException
@@ -63,18 +62,16 @@ object Build {
6362
def foundMainClass =
6463
if (foundMainClasses0.isEmpty) Left(new NoMainClassFoundError)
6564
else if (foundMainClasses0.length == 1) Right(foundMainClasses0.head)
66-
else {
67-
val msg = "Found several main classes. Which would you like to run?"
68-
val fallbackError = new SeveralMainClassesFoundError(
69-
::(foundMainClasses0.head, foundMainClasses0.tail.toList),
70-
Nil
71-
)
72-
Interactive(options).chooseOne(
73-
msg,
74-
foundMainClasses0.toList,
75-
fallbackError
76-
)
77-
}
65+
else
66+
options.interactive.chooseOne(
67+
"Found several main classes. Which would you like to run?",
68+
foundMainClasses0.toList
69+
).toRight {
70+
new SeveralMainClassesFoundError(
71+
::(foundMainClasses0.head, foundMainClasses0.tail.toList),
72+
Nil
73+
)
74+
}
7875

7976
defaultMainClassOpt match {
8077
case Some(cls) => Right(cls)

modules/build/src/main/scala/scala/build/interactive/Interactive.scala

Lines changed: 0 additions & 44 deletions
This file was deleted.

modules/cli-options/src/main/scala/scala/cli/commands/SharedOptions.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,6 @@ final case class SharedOptions(
101101

102102
@Hidden
103103
strictBloopJsonCheck: Option[Boolean] = None,
104-
@HelpMessage("Interactive mode")
105-
@Name("i")
106-
interactive: Option[Boolean] = None
107104
)
108105
// format: on
109106

modules/cli-options/src/main/scala/scala/cli/commands/VerbosityOptions.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ final case class VerbosityOptions(
99
@Group("Logging")
1010
@HelpMessage("Increase verbosity (can be specified multiple times)")
1111
@Name("v")
12-
verbose: Int @@ Counter = Tag.of(0)
12+
verbose: Int @@ Counter = Tag.of(0),
13+
@HelpMessage("Interactive mode")
14+
@Name("i")
15+
interactive: Option[Boolean] = None
1316
) {
1417
// format: on
1518

modules/cli/src/main/scala/scala/cli/commands/Doc.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import scala.build.EitherCps.{either, value}
99
import scala.build._
1010
import scala.build.compiler.{ScalaCompilerMaker, SimpleScalaCompilerMaker}
1111
import scala.build.errors.BuildException
12+
import scala.build.interactive.InteractiveFileOps
1213
import scala.build.internal.Runner
1314
import scala.cli.CurrentParams
1415
import scala.cli.commands.util.SharedOptionsUtil._
@@ -78,11 +79,12 @@ object Doc extends ScalaCommand[DocOptions] {
7879

7980
def alreadyExistsCheck(): Unit = {
8081
val alreadyExists = !force && os.exists(destPath)
81-
if (alreadyExists) {
82-
val msg = s"$printableDest already exists"
83-
System.err.println(s"Error: $msg. Pass -f or --force to force erasing it.")
84-
sys.exit(1)
85-
}
82+
if (alreadyExists)
83+
InteractiveFileOps.erasingPath(build.options.interactive, printableDest, destPath) { () =>
84+
val msg = s"$printableDest already exists"
85+
System.err.println(s"Error: $msg. Pass -f or --force to force erasing it.")
86+
sys.exit(1)
87+
}
8688
}
8789

8890
alreadyExistsCheck()

modules/cli/src/main/scala/scala/cli/commands/Fmt.scala

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package scala.cli.commands
22

33
import caseapp._
44

5+
import scala.build.interactive.InteractiveFileOps
56
import scala.build.internal.{Constants, CustomCodeWrapper, FetchExternalBinary, Runner}
67
import scala.build.options.BuildOptions
78
import scala.build.{CrossSources, Inputs, Logger, Sources}
89
import scala.cli.CurrentParams
910
import scala.cli.commands.util.SharedOptionsUtil._
11+
import scala.cli.commands.util.VerbosityOptionsUtil._
1012
import scala.util.Properties
1113
import scala.util.control.NonFatal
1214

@@ -97,7 +99,8 @@ object Fmt extends ScalaCommand[FmtOptions] {
9799

98100
def run(options: FmtOptions, args: RemainingArgs): Unit = {
99101
CurrentParams.verbosity = options.shared.logging.verbosity
100-
val logger = options.shared.logger
102+
val interactive = options.shared.logging.verbosityOptions.interactiveInstance
103+
val logger = options.shared.logger
101104

102105
// TODO If no input is given, just pass '.' to scalafmt?
103106
val (sourceFiles, workspace, inputsOpt) =
@@ -112,16 +115,24 @@ object Fmt extends ScalaCommand[FmtOptions] {
112115
(s, i.workspace, Some(i))
113116
}
114117
CurrentParams.workspaceOpt = Some(workspace)
115-
val (versionMaybe, confExists) = readVersionFromFile(workspace, logger)
116-
val cache = options.shared.buildOptions().archiveCache
118+
val (versionMaybe, confExists0) = readVersionFromFile(workspace, logger)
119+
val cache = options.shared.buildOptions().archiveCache
120+
val buildOptions = options.buildOptions
117121

118-
val version = versionMaybe.getOrElse {
119-
System.err.println(
122+
val (version, confExists) = versionMaybe.map((_, confExists0)).getOrElse {
123+
val errorMsg =
120124
s"""|Scalafmt requires explicitly specified version.
121125
|To configure the scalafmt version add the following line into .scalafmt.conf:
122126
| version = ${Constants.defaultScalafmtVersion} """.stripMargin
123-
)
124-
sys.exit(1)
127+
val msg = s"""|$errorMsg
128+
|Do you want to add Scalafmt version to .scalafmt.conf file?""".stripMargin
129+
val scalafmtConfPath = workspace / ".scalafmt"
130+
val entry = s"version = ${Constants.defaultScalafmtVersion}${System.lineSeparator()}"
131+
InteractiveFileOps.appendToFile(interactive, msg, scalafmtConfPath, entry) { () =>
132+
System.err.println(errorMsg)
133+
sys.exit(1)
134+
}
135+
(Constants.defaultScalafmtVersion, true)
125136
}
126137

127138
if (sourceFiles.isEmpty)
@@ -133,11 +144,11 @@ object Fmt extends ScalaCommand[FmtOptions] {
133144
CrossSources.forInputs(
134145
inputs,
135146
Sources.defaultPreprocessors(
136-
options.buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper)
147+
buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper)
137148
),
138149
logger
139150
).orExit(logger)
140-
val sharedOptions = crossSources.sharedOptions(options.buildOptions)
151+
val sharedOptions = crossSources.sharedOptions(buildOptions)
141152
sharedOptions
142153
.scalaParams
143154
.orExit(logger)

modules/cli/src/main/scala/scala/cli/commands/InstallCompletions.scala

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import java.util.Arrays
99

1010
import scala.cli.CurrentParams
1111
import scala.cli.commands.util.CommonOps._
12+
import scala.cli.commands.util.VerbosityOptionsUtil._
1213
import scala.cli.internal.{Argv0, ProfileFileUpdater}
1314

1415
object InstallCompletions extends ScalaCommand[InstallCompletionsOptions] {
@@ -19,7 +20,7 @@ object InstallCompletions extends ScalaCommand[InstallCompletionsOptions] {
1920
private lazy val home = os.Path(sys.props("user.home"), os.pwd)
2021
def run(options: InstallCompletionsOptions, args: RemainingArgs): Unit = {
2122
CurrentParams.verbosity = options.logging.verbosity
22-
23+
val interactive = options.logging.verbosityOptions.interactiveInstance
2324
lazy val completionsDir =
2425
options.output
2526
.map(os.Path(_, os.pwd))
@@ -43,12 +44,15 @@ object InstallCompletions extends ScalaCommand[InstallCompletionsOptions] {
4344
}
4445
}
4546
.getOrElse {
46-
System.err.println(
47-
"Cannot determine current shell, pass the shell you use with --shell, like"
48-
)
49-
System.err.println(s" $name install completions --shell zsh")
50-
System.err.println(s" $name install completions --shell bash")
51-
sys.exit(1)
47+
val msg = "Cannot determine current shell. Which would you like to use?"
48+
interactive.chooseOne(msg, List("zsh", "bash")).getOrElse {
49+
System.err.println(
50+
"Cannot determine current shell, pass the shell you use with --shell, like"
51+
)
52+
System.err.println(s" $name install completions --shell zsh")
53+
System.err.println(s" $name install completions --shell bash")
54+
sys.exit(1)
55+
}
5256
}
5357

5458
val (rcScript, defaultRcFile) = format match {

modules/cli/src/main/scala/scala/cli/commands/Package.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import java.util.zip.{ZipEntry, ZipOutputStream}
1818
import scala.build.EitherCps.{either, value}
1919
import scala.build._
2020
import scala.build.errors.{BuildException, MalformedCliInputError, ScalaNativeBuildError}
21+
import scala.build.interactive.InteractiveFileOps
2122
import scala.build.internal.{Runner, ScalaJsLinkerConfig}
2223
import scala.build.options.{PackageType, Platform}
2324
import scala.cli.CurrentParams
@@ -221,13 +222,14 @@ object Package extends ScalaCommand[PackageOptions] {
221222
val alreadyExists = !force &&
222223
os.exists(destPath) &&
223224
!expectedModifyEpochSecondOpt.contains(os.mtime(destPath))
224-
if (alreadyExists) {
225-
val msg =
226-
if (expectedModifyEpochSecondOpt.isEmpty) s"$printableDest already exists"
227-
else s"$printableDest was overwritten by another process"
228-
System.err.println(s"Error: $msg. Pass -f or --force to force erasing it.")
229-
sys.exit(1)
230-
}
225+
if (alreadyExists)
226+
InteractiveFileOps.erasingPath(build.options.interactive, printableDest, destPath) { () =>
227+
val errorMsg =
228+
if (expectedModifyEpochSecondOpt.isEmpty) s"$printableDest already exists"
229+
else s"$printableDest was overwritten by another process"
230+
System.err.println(s"Error: $errorMsg. Pass -f or --force to force erasing it.")
231+
sys.exit(1)
232+
}
231233
}
232234

233235
alreadyExistsCheck()

modules/cli/src/main/scala/scala/cli/commands/Update.scala

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import com.github.plokhotnyuk.jsoniter_scala.macros._
77
import scala.build.Logger
88
import scala.build.internal.Constants.{ghName, ghOrg, version => scalaCliVersion}
99
import scala.cli.CurrentParams
10+
import scala.cli.commands.util.VerbosityOptionsUtil._
1011
import scala.cli.internal.ProcUtil
1112
import scala.cli.signing.shared.Secret
12-
import scala.io.StdIn.readLine
1313
import scala.util.Properties
1414
import scala.util.control.NonFatal
1515

@@ -59,19 +59,15 @@ object Update extends ScalaCommand[UpdateOptions] {
5959
)
6060

6161
private def updateScalaCli(options: UpdateOptions, newVersion: String) = {
62-
if (!options.force)
63-
if (coursier.paths.Util.useAnsiOutput()) {
64-
println(s"Do you want to update scala-cli to version $newVersion [Y/n]")
65-
val response = readLine()
66-
if (response.toLowerCase != "y") {
67-
System.err.println("Abort")
68-
sys.exit(1)
69-
}
70-
}
71-
else {
62+
val interactive = options.verbosity.interactiveInstance
63+
if (!options.force) {
64+
val fallbackAction = () => {
7265
System.err.println(s"To update scala-cli to $newVersion pass -f or --force")
7366
sys.exit(1)
7467
}
68+
val msg = s"Do you want to update scala-cli to version $newVersion?"
69+
interactive.confirmOperation(msg).getOrElse(fallbackAction())
70+
}
7571

7672
val installationScript =
7773
ProcUtil.downloadFile("https://virtuslab.github.io/scala-cli-packages/scala-setup.sh")

modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ object SharedOptionsUtil {
147147
localRepository = LocalRepo.localRepo(directories.directories.localRepoDir),
148148
verbosity = Some(logging.verbosity),
149149
strictBloopJsonCheck = strictBloopJsonCheck,
150-
interactive = interactive
150+
interactive = logging.verbosityOptions.interactive
151151
),
152152
notForBloopOptions = bo.PostBuildOptions(
153153
scalaJsLinkerOptions = linkerOptions(js)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package scala.cli.commands
2+
package util
3+
4+
import scala.build.interactive.Interactive._
5+
6+
object VerbosityOptionsUtil {
7+
implicit class VerbosityOptionsOps(v: VerbosityOptions) {
8+
val interactiveInstance = if (v.interactive.getOrElse(false)) InteractiveAsk else InteractiveNop
9+
}
10+
}

0 commit comments

Comments
 (0)