From 563bcb93aa17276a4ff53540a75a11dc2b59c7d3 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 21 Sep 2019 18:28:16 -0400 Subject: [PATCH] Throw error if you run sbt from / Fixes #1458 Running sbt from `/` results to sbt getting stuck trying to load the directories recursively, and eventually erroring with a java.lang.OutOfMemoryError (after freezing for a long time) even on an Alpine container. To prevent it, this adds a check to see if the absolute path is `/` or not. ``` / $ sbt -Dsbt.version=1.4.0-SNAPSHOT [error] java.lang.IllegalStateException: cannot run sbt from root directory without -Dsbt.rootdir=true; see sbt/sbt#1458 [error] Use 'last' for the full log. ``` --- main/src/main/scala/sbt/Main.scala | 25 ++++++++++++++++--- .../src/main/scala/sbt/internal/SysProp.scala | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 4e515baaa..7826e9caf 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -9,7 +9,7 @@ package sbt import java.io.{ File, IOException } import java.net.URI -import java.nio.file.{ FileAlreadyExistsException, Files } +import java.nio.file.{ FileAlreadyExistsException, Files, FileSystems } import java.util.concurrent.ForkJoinPool import java.util.concurrent.atomic.AtomicBoolean import java.util.{ Locale, Properties } @@ -940,14 +940,33 @@ object BuiltinCommands { state.remainingCommands exists (_.commandLine == TemplateCommand) private def writeSbtVersion(state: State) = - if (SysProp.genBuildProps && !intendsToInvokeNew(state)) + if (SysProp.genBuildProps && !intendsToInvokeNew(state)) { writeSbtVersionUnconditionally(state) + } + + private def checkRoot(state: State): Unit = + if (SysProp.allowRootDir) () + else { + val baseDir = state.baseDir + import scala.collection.JavaConverters._ + // this should return / on Unix and C:\ for Windows. + val rootOpt = FileSystems.getDefault.getRootDirectories.asScala.toList.headOption + rootOpt foreach { root => + if (baseDir.getAbsolutePath == root.toString) { + throw new IllegalStateException( + "cannot run sbt from root directory without -Dsbt.rootdir=true; see sbt/sbt#1458" + ) + } + } + } private def WriteSbtVersion = "writeSbtVersion" private def writeSbtVersion: Command = Command.command(WriteSbtVersion) { state => - writeSbtVersion(state); state + checkRoot(state) + writeSbtVersion(state) + state } private def intendsToInvokeCompile(state: State) = diff --git a/main/src/main/scala/sbt/internal/SysProp.scala b/main/src/main/scala/sbt/internal/SysProp.scala index 72f4af731..defeb726f 100644 --- a/main/src/main/scala/sbt/internal/SysProp.scala +++ b/main/src/main/scala/sbt/internal/SysProp.scala @@ -69,6 +69,7 @@ object SysProp { def traces: Boolean = getOrFalse("sbt.traces") def client: Boolean = getOrFalse("sbt.client") def ci: Boolean = getOrFalse("sbt.ci") + def allowRootDir: Boolean = getOrFalse("sbt.rootdir") def watchMode: String = sys.props.get("sbt.watch.mode").getOrElse("auto")