Skip to content

Commit

Permalink
improve the error message when Scala version was not detected
Browse files Browse the repository at this point in the history
When Scala version is set to `auto`, and for some reason the resolution is incomplete (it seems to happen at CI more frequently than normal lately), the launcher will print out the following error message.

## before

```
error during sbt execution: No Scala version specified or detected
```

## after

now it will print this instead:

```
[error] [launcher] error during sbt launcher: sbt/sbt#4955!
[error] [launcher] sbt launcher is unable to detect the Scala version for jline:jline;
[error] [launcher] this likely indicates an incomplete artifact resolution and/or corrupt boot cache (~/.sbt/boot/).
[error] [launcher] the following is the full classpath that was retrieved for jline:jline:
[error] [launcher]  * /tmp/boot/other/jline/jline/2.14.6/jline-2.14.6.jar
```
  • Loading branch information
eed3si9n committed Aug 19, 2019
1 parent 2eb0108 commit 3861e8a
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 23 deletions.
8 changes: 5 additions & 3 deletions launcher-implementation/src/main/scala/xsbt/boot/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ object Boot {
val sec = Duration(s).toSeconds
if (sec >= 1) {
(sec to 1 by -1) foreach { i =>
Console.err.println(s"[info] standing by: $i")
Console.err.println(s"[info] [launcher] standing by: $i")
Thread.sleep(1000)
}
}
Expand Down Expand Up @@ -56,15 +56,17 @@ object Boot {
Launch(args) map exit
catch {
case b: BootException => errorAndExit(b.toString)
case r: xsbti.RetrieveException => errorAndExit("Error: " + r.getMessage)
case r: xsbti.RetrieveException => errorAndExit(r.getMessage)
case r: xsbti.FullReload => Some(new LauncherArguments(r.arguments.toList, false))
case e: Throwable =>
e.printStackTrace
errorAndExit(Pre.prefixError(e.toString))
}

private def errorAndExit(msg: String): Nothing = {
Console.err.println(msg)
msg.linesIterator.toList foreach { line =>
Console.err.println("[error] [launcher] " + line)
}
exit(1)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ object CheckProxy {
copyEnv(envPassword, sysPassword)
} catch {
case e: MalformedURLException =>
Console.err.println(s"[warn] could not parse $envURL setting: ${e.toString}")
Console.err.println(s"[warn] [launcher] could not parse $envURL setting: ${e.toString}")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ object Configuration {
}
def setProperty(head: String): Unit = {
head.split("=", 2) match {
case Array("") => Console.err.println(s"[warn] invalid system property '$head'")
case Array("") => Console.err.println(s"[warn] [launcher] invalid system property '$head'")
case Array(key) => sys.props += key -> ""
case Array(key, value) => sys.props += key -> value
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Find(config: LaunchConfiguration) {
case Nil => Some(current)
case head :: Nil => Some(head)
case xs =>
Console.err.println("search method is 'only' and multiple ancestor directories match:\n\t" + fromRoot.mkString("\n\t"))
Console.err.println("[error] [launcher] search method is 'only' and multiple ancestor directories match:\n\t" + fromRoot.mkString("\n\t"))
System.exit(1)
None
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ object JAnsi {
* mitigation code that should not render sbt completely unusable if jansi initialization fails.
* [From Mark Harrah, https://github.com/sbt/sbt/pull/633#issuecomment-11957578].
*/
case ex: Throwable => Console.err.println("Jansi found on class path but initialization failed: " + ex)
case ex: Throwable => Console.err.println("[error] [launcher] Jansi found on class path but initialization failed: " + ex)
}
}
13 changes: 11 additions & 2 deletions launcher-implementation/src/main/scala/xsbt/boot/Launch.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ object Launch {
if (arguments.isLocate) {
if (!newArgs2.isEmpty) {
// TODO - Print the arguments without exploding proguard size.
Console.err.println("[warn] --locate option ignores arguments")
Console.err.println("[warn] [launcher] --locate option ignores arguments")
}
locate(currentDirectory, config)
} else {
Expand Down Expand Up @@ -224,7 +224,16 @@ class Launch private[xsbt] (val bootDirectory: File, val lockBoot: Boolean, val
retrievedApp.fullClasspath.find(f => testInterface.matcher(f.getName).find()).foreach { f =>
scalaProviderClassLoader.set(TestInterfaceLoader(f, initLoader))
}
val scalaVersion = getOrError(strictOr(explicitScalaVersion, retrievedApp.detectedScalaVersion), "No Scala version specified or detected")
// https://github.com/sbt/sbt/issues/4955
// When sbt core artifacts are not properly downloaded, this the point that fails with "No Scala version specified or detected"
val scalaVersion = getOrError(
strictOr(explicitScalaVersion, retrievedApp.detectedScalaVersion),
s"""sbt/sbt#4955!
|sbt launcher is unable to detect the Scala version for ${id.groupID}:${id.name};
|this likely indicates an incomplete artifact resolution and/or corrupt boot cache (~/.sbt/boot/).
|the following is the full classpath that was retrieved for ${id.groupID}:${id.name}:
|""".stripMargin ++ retrievedApp.fullClasspath.toList.map(x => " * " + x.getAbsolutePath).mkString(System.lineSeparator)
)
val scalaProvider = getScala(scalaVersion, "(for " + id.name + ")")
val resolvedId = resolveId(retrievedApp.resolvedAppVersion, id)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ object Locks extends xsbti.GlobalLock {
{
val freeLock = try { channel.tryLock } catch { case e: NullPointerException => throw new InternalLockNPE(e) }
if (freeLock eq null) {
Console.err.println("waiting for lock on " + file + " to be available...");
Console.err.println("[info] waiting for lock on " + file + " to be available...");
val lock = try { channel.lock } catch { case e: NullPointerException => throw new InternalLockNPE(e) }
try { run.call }
finally { lock.release() }
Expand Down
2 changes: 1 addition & 1 deletion launcher-implementation/src/main/scala/xsbt/boot/Pre.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ object Pre {
def require(condition: Boolean, msg: => String): Unit = if (!condition) throw new IllegalArgumentException(msg)
def error(msg: String): Nothing = throw new BootException(prefixError(msg))
def declined(msg: String): Nothing = throw new BootException(msg)
def prefixError(msg: String): String = "error during sbt execution: " + msg
def prefixError(msg: String): String = "error during sbt launcher: " + msg
def toBoolean(s: String) = java.lang.Boolean.parseBoolean(s)
def toArray[T: ClassManifest](list: List[T]) =
{
Expand Down
28 changes: 16 additions & 12 deletions launcher-implementation/src/main/scala/xsbt/boot/Update.scala
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ final class Update(config: UpdateConfiguration) {
catch {
case e: Exception =>
e.printStackTrace(logWriter)
log(e.toString)
log("[error] [launcher] " + e.toString)
Console.err.println(" (see " + logFile + " for complete log)")
new UpdateResult(false, None, None)
} finally {
Expand All @@ -130,8 +130,8 @@ final class Update(config: UpdateConfiguration) {
addDependency(moduleID, scalaOrg, CompilerModuleName, scalaVersion, "default;optional(default)", u.classifiers)
val ddesc = addDependency(moduleID, scalaOrg, LibraryModuleName, scalaVersion, "default", u.classifiers)
excludeJUnit(moduleID)
val scalaOrgString = if (scalaOrg != ScalaOrg) " " + scalaOrg else ""
Console.err.println(s"[info] getting $scalaOrgString Scala $scalaVersion ${reason}...")
val scalaOrgString = if (scalaOrg != ScalaOrg) scalaOrg + " " else ""
Console.err.println(s"[info] [launcher] getting ${scalaOrgString}Scala $scalaVersion ${reason}...")
ddesc.getDependencyId
case u: UpdateApp =>
val app = u.id
Expand All @@ -141,7 +141,7 @@ final class Update(config: UpdateConfiguration) {
case _ => app.getName
}
val ddesc = addDependency(moduleID, app.groupID, resolvedName, app.getVersion, "default(compile)", u.classifiers)
Console.err.println(s"[info] getting ${app.groupID} $resolvedName ${app.getVersion} $reason (this may take some time)...")
Console.err.println(s"[info] [launcher] getting ${app.groupID} $resolvedName ${app.getVersion} $reason (this may take some time)...")
ddesc.getDependencyId
}
update(moduleID, target, dep)
Expand Down Expand Up @@ -205,7 +205,10 @@ final class Update(config: UpdateConfiguration) {
logExceptions(resolveReport)
val seen = new java.util.LinkedHashSet[Any]
seen.addAll(resolveReport.getAllProblemMessages)
Console.err.println(seen.toArray.mkString(System.getProperty("line.separator")))
Console.err.println(
seen.toArray.map(x => s"[error] [launcher] $x")
.mkString(System.getProperty("line.separator"))
)
error("error retrieving required libraries")
}
val modules = moduleRevisionIDs(resolveReport)
Expand Down Expand Up @@ -320,12 +323,12 @@ final class Update(config: UpdateConfiguration) {
case MavenCentral =>
mavenMainResolver
case ScalaToolsReleases =>
log(s"$ScalaToolsReleases deprecated. use $SonatypeOSSReleases instead.")
log(s"[warn] [launcher] $ScalaToolsReleases deprecated. use $SonatypeOSSReleases instead.")
sonatypeReleases
case SonatypeOSSReleases =>
sonatypeReleases
case ScalaToolsSnapshots =>
log(s"$ScalaToolsSnapshots deprecated. use $SonatypeOSSSnapshots instead.")
log(s"[warn] [launcher] $ScalaToolsSnapshots deprecated. use $SonatypeOSSSnapshots instead.")
scalaSnapshots(getScalaVersion)
case SonatypeOSSSnapshots =>
scalaSnapshots(getScalaVersion)
Expand Down Expand Up @@ -368,15 +371,15 @@ final class Update(config: UpdateConfiguration) {
private def centralRepositoryRoot(secure: Boolean) = {
val value = (if (secure) "https" else "http") + "://repo1.maven.org/maven2/"
if (!secure) {
log(s"[warn] insecure HTTP request is deprecated '$value' via 'sbt.repository.secure'; switch to HTTPS")
log(s"[warn] Maven Central HTTP access is scheduled to end in January 2020")
log(s"[warn] [launcher] insecure HTTP request is deprecated '$value' via 'sbt.repository.secure'; switch to HTTPS")
log(s"[warn] [launcher] Maven Central HTTP access is scheduled to end in January 2020")
}
value
}
private def jcenterRepositoryRoot(secure: Boolean) = {
val value = (if (secure) "https" else "http") + "://jcenter.bintray.com/"
if (!secure) {
log(s"[warn] insecure HTTP request is deprecated '$value' via 'sbt.repository.secure'; switch to HTTPS")
log(s"[warn] [launcher] insecure HTTP request is deprecated '$value' via 'sbt.repository.secure'; switch to HTTPS")
}
value
}
Expand Down Expand Up @@ -417,7 +420,7 @@ final class Update(config: UpdateConfiguration) {
private def log(msg: String) =
{
try { logWriter.println(msg) }
catch { case e: Exception => Console.err.println("error writing to update log file: " + e.toString) }
catch { case e: Exception => Console.err.println("[error] [launcher] error writing to update log file: " + e.toString) }
Console.err.println(msg)
}
}
Expand All @@ -433,8 +436,9 @@ private final class SbtIvyLogger(logWriter: PrintWriter) extends DefaultMessageL
if (isAlwaysIgnoreMessage(msg)) ()
else {
logWriter.println(msg)
if (level <= getLevel && acceptMessage(msg))
if (level <= getLevel && acceptMessage(msg)) {
Console.err.println(msg)
}
}
override def rawlog(msg: String, level: Int): Unit = { log(msg, level) }
/** This is a hack to filter error messages about 'unknown resolver ...'. */
Expand Down

0 comments on commit 3861e8a

Please sign in to comment.