diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f6f5de34e..846327e2aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: JVM_OPTS: -Xms800M -Xmx2G -Xss6M -XX:ReservedCodeCacheSize=128M -server -Dsbt.io.virtual=false -Dfile.encoding=UTF-8 SCALA_212: 2.12.20 UTIL_TESTS: "utilCache/test utilControl/test utilInterface/test utilLogging/test utilPosition/test utilRelation/test utilScripted/test utilTracking/test" - TEST_SBT_VER: 1.10.5 + TEST_SBT_VER: 1.10.7 SBT_ETC_FILE: $HOME/etc/sbt/sbtopts JDK11: adopt@1.11.0-9 SPARK_LOCAL_IP: "127.0.0.1" @@ -142,18 +142,18 @@ jobs: shell: bash run: | ./sbt -v "++2.13.x; all utilControl/test utilRelation/test utilPosition/test" -# - name: Multirepo integration test -# if: ${{ matrix.jobtype == 6 }} -# shell: bash -# run: | -# # build from fresh IO, LM, and Zinc -# BUILD_VERSION="${TEST_SBT_VER}-SNAPSHOT" -# cd io -# sbt -v -Dsbt.build.version=${BUILD_VERSION} +publishLocal -# cd ../ -# sbt -Dsbtlm.path=$HOME/work/sbt/sbt/librarymanagement -Dsbtzinc.path=$HOME/work/sbt/sbt/zinc -Dsbt.build.version=$BUILD_VERSION -Dsbt.build.fatal=false "+lowerUtils/publishLocal; {librarymanagement}/publishLocal; {zinc}/publishLocal; upperModules/publishLocal" -# rm -r $(find $HOME/.sbt/boot -name "*-SNAPSHOT") || true -# sbt -v -Dsbt.version=$BUILD_VERSION "++2.13.x; all $UTIL_TESTS; ++$SCALA_212; all $UTIL_TESTS; scripted actions/* source-dependencies/*1of3 dependency-management/*1of4 java/*" + - name: Multirepo integration test + if: ${{ matrix.jobtype == 6 }} + shell: bash + run: | + # build from fresh IO, LM, and Zinc + BUILD_VERSION="${TEST_SBT_VER}-SNAPSHOT" + cd io + sbt -v -Dsbt.build.version=${BUILD_VERSION} +publishLocal + cd ../ + sbt -Dsbtlm.path=$HOME/work/sbt/sbt/librarymanagement -Dsbtzinc.path=$HOME/work/sbt/sbt/zinc -Dsbt.build.version=$BUILD_VERSION -Dsbt.build.fatal=false "+lowerUtils/publishLocal; {librarymanagement}/publishLocal; {zinc}/publishLocal; upperModules/publishLocal" + rm -r $(find $HOME/.sbt/boot -name "*-SNAPSHOT") || true + sbt -v -Dsbt.version=$BUILD_VERSION "++2.13.x; all $UTIL_TESTS; ++$SCALA_212; all $UTIL_TESTS; scripted actions/* source-dependencies/*1of3 dependency-management/*1of4 java/*" - name: Build and test (7) if: ${{ matrix.jobtype == 7 }} shell: bash diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index f9ead39fdc..c7ec83e666 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -4,21 +4,7 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Check CLA - env: - AUTHOR: ${{ github.event.pull_request.user.login }} - run: | - echo "Pull request submitted by $AUTHOR"; - signed=$(curl -s "https://www.lightbend.com/contribute/cla/scala/check/$AUTHOR" | jq -r ".signed"); - if [ "$signed" = "true" ] ; then - echo "CLA check for $AUTHOR successful"; - else - echo "CLA check for $AUTHOR failed"; - echo "Please sign the Scala CLA to contribute to the Scala compiler."; - echo "Go to https://www.lightbend.com/contribute/cla/scala and then"; - echo "comment on the pull request to ask for a new check."; - echo ""; - echo "Check if CLA is signed: https://www.lightbend.com/contribute/cla/scala/check/$AUTHOR"; - exit 1; - fi; + - name: Check CLA + uses: scala/cla-checker@v1 + with: + author: ${{ github.event.pull_request.user.login }} diff --git a/build.sbt b/build.sbt index 81949a48ca..eebbfdd3cd 100644 --- a/build.sbt +++ b/build.sbt @@ -11,7 +11,7 @@ import scala.util.Try // ThisBuild settings take lower precedence, // but can be shared across the multi projects. ThisBuild / version := { - val v = "1.10.6-SNAPSHOT" + val v = "1.10.8-SNAPSHOT" nightlyVersion.getOrElse(v) } ThisBuild / version2_13 := "2.0.0-SNAPSHOT" diff --git a/internal/util-scripted/src/main/scala/sbt/internal/scripted/FileCommands.scala b/internal/util-scripted/src/main/scala/sbt/internal/scripted/FileCommands.scala index 1de3ff6075..a8bd975446 100644 --- a/internal/util-scripted/src/main/scala/sbt/internal/scripted/FileCommands.scala +++ b/internal/util-scripted/src/main/scala/sbt/internal/scripted/FileCommands.scala @@ -11,11 +11,15 @@ package internal package scripted import java.io.File +import sbt.nio.file.{ FileTreeView, Glob, PathFilter, RecursiveGlob } import sbt.io.{ IO, Path } import sbt.io.syntax._ import Path._ class FileCommands(baseDirectory: File) extends BasicStatementHandler { + final val OR = "||" + lazy val view = FileTreeView.Ops(FileTreeView.default) + val baseGlob = Glob(baseDirectory) lazy val commands = commandMap def commandMap = Map( @@ -51,8 +55,42 @@ class FileCommands(baseDirectory: File) extends BasicStatementHandler { def spaced[T](l: Seq[T]) = l.mkString(" ") def fromStrings(paths: List[String]) = paths.map(fromString) def fromString(path: String) = new File(baseDirectory, path) + def filterFromStrings(exprs: List[String]): List[PathFilter] = { + def globs(exprs: List[String]): List[PathFilter] = + exprs.map { g => + if (g.startsWith("/")) (Glob(g): PathFilter) + else (Glob(baseDirectory, g): PathFilter) + } + def orGlobs = { + val exprs1 = exprs + .mkString("") + .split(OR) + .filter(_ != OR) + .toList + .map(_.trim) + val combined = globs(exprs1) match { + case Nil => sys.error("unexpected Nil") + case g :: Nil => g + case g :: gs => + gs.foldLeft(g) { + case (acc, g) => acc || g + } + } + List(combined) + } + if (exprs.contains("||")) orGlobs + else globs(exprs) + } + def touch(paths: List[String]): Unit = IO.touch(fromStrings(paths)) - def delete(paths: List[String]): Unit = IO.delete(fromStrings(paths)) + def delete(paths: List[String]): Unit = + IO.delete( + (filterFromStrings(paths) + .flatMap { filter => + view.list(baseGlob / RecursiveGlob, filter) + }) + .map(_._1.toFile) + ) /*def sync(from: String, to: String) = IO.sync(fromString(from), fromString(to), log)*/ def copyFile(from: String, to: String): Unit = @@ -78,13 +116,16 @@ class FileCommands(baseDirectory: File) extends BasicStatementHandler { scriptError(s"$pathA is not newer than $pathB") } } + // use FileTreeView to test if a file with the given filter exists + def exists0(filter: PathFilter): Boolean = + view.list(baseGlob / RecursiveGlob, filter).nonEmpty def exists(paths: List[String]): Unit = { - val notPresent = fromStrings(paths).filter(!_.exists) + val notPresent = filterFromStrings(paths).filter(!exists0(_)) if (notPresent.nonEmpty) scriptError("File(s) did not exist: " + notPresent.mkString("[ ", " , ", " ]")) } def absent(paths: List[String]): Unit = { - val present = fromStrings(paths).filter(_.exists) + val present = filterFromStrings(paths).filter(exists0) if (present.nonEmpty) scriptError("File(s) existed: " + present.mkString("[ ", " , ", " ]")) } diff --git a/launcher-package/integration-test/src/test/scala/RunnerTest.scala b/launcher-package/integration-test/src/test/scala/RunnerTest.scala index f3d4065026..382b259d77 100755 --- a/launcher-package/integration-test/src/test/scala/RunnerTest.scala +++ b/launcher-package/integration-test/src/test/scala/RunnerTest.scala @@ -4,6 +4,7 @@ import minitest._ import scala.sys.process._ import java.io.File import java.util.Locale +import sbt.io.IO object SbtRunnerTest extends SimpleTestSuite with PowerAssertions { // 1.3.0, 1.3.0-M4 @@ -20,6 +21,10 @@ object SbtRunnerTest extends SimpleTestSuite with PowerAssertions { sbt.internal.Process(Seq(sbtScript.getAbsolutePath) ++ args, new File("citest"), "JAVA_OPTS" -> javaOpts, "SBT_OPTS" -> sbtOpts) + def sbtProcessInDir(dir: File)(args: String*) = + sbt.internal.Process(Seq(sbtScript.getAbsolutePath) ++ args, dir, + "JAVA_OPTS" -> "", + "SBT_OPTS" -> "") test("sbt runs") { assert(sbtScript.exists) @@ -68,6 +73,27 @@ object SbtRunnerTest extends SimpleTestSuite with PowerAssertions { } } + test("sbt in empty directory") { + IO.withTemporaryDirectory { tmp => + val out = sbtProcessInDir(tmp)("about").! + assert(out == 1) + } + IO.withTemporaryDirectory { tmp => + val out = sbtProcessInDir(tmp)("about", "--allow-empty").! + assert(out == 0) + } + () + } + + test("sbt --script-version in empty directory") { + IO.withTemporaryDirectory { tmp => + val out = sbtProcessInDir(tmp)("--script-version").!!.trim + val expectedVersion = "^"+versionRegEx+"$" + assert(out.matches(expectedVersion)) + } + () + } + /* test("sbt --client") { val out = sbtProcess("--client", "--no-colors", "compile").!!.linesIterator.toList diff --git a/launcher-package/src/universal/bin/sbt.bat b/launcher-package/src/universal/bin/sbt.bat index f9d6ce6fd9..2bd4dd49e6 100755 --- a/launcher-package/src/universal/bin/sbt.bat +++ b/launcher-package/src/universal/bin/sbt.bat @@ -45,7 +45,7 @@ set sbt_args_timings= set sbt_args_traces= set sbt_args_sbt_boot= set sbt_args_sbt_cache= -set sbt_args_sbt_create= +set sbt_args_allow_empty= set sbt_args_sbt_dir= set sbt_args_sbt_version= set sbt_args_mem= @@ -72,11 +72,13 @@ rem TODO: remove/deprecate sbtconfig.txt and parse the sbtopts files rem FIRST we load the config file of extra options. set SBT_CONFIG=!SBT_HOME!\conf\sbtconfig.txt set SBT_CFG_OPTS= -for /F "tokens=* eol=# usebackq delims=" %%i in ("!SBT_CONFIG!") do ( - set DO_NOT_REUSE_ME=%%i - rem ZOMG (Part #2) WE use !! here to delay the expansion of - rem SBT_CFG_OPTS, otherwise it remains "" for this loop. - set SBT_CFG_OPTS=!SBT_CFG_OPTS! !DO_NOT_REUSE_ME! +if exist "!SBT_CONFIG!" ( + for /F "tokens=* eol=# usebackq delims=" %%i in ("!SBT_CONFIG!") do ( + set DO_NOT_REUSE_ME=%%i + rem ZOMG (Part #2) WE use !! here to delay the expansion of + rem SBT_CFG_OPTS, otherwise it remains "" for this loop. + set SBT_CFG_OPTS=!SBT_CFG_OPTS! !DO_NOT_REUSE_ME! + ) ) rem poor man's jenv (which is not available on Windows) @@ -235,12 +237,14 @@ if defined _traces_arg ( goto args_loop ) -if "%~0" == "-sbt-create" set _sbt_create_arg=true -if "%~0" == "--sbt-create" set _sbt_create_arg=true +if "%~0" == "-sbt-create" set _allow_empty_arg=true +if "%~0" == "--sbt-create" set _allow_empty_arg=true +if "%~0" == "-allow-empty" set _allow_empty_arg=true +if "%~0" == "--allow-empty" set _allow_empty_arg=true -if defined _sbt_create_arg ( - set _sbt_create_arg= - set sbt_args_sbt_create=1 +if defined _allow_empty_arg ( + set _allow_empty_arg= + set sbt_args_allow_empty=1 goto args_loop ) @@ -526,25 +530,12 @@ goto args_loop rem Confirm a user's intent if the current directory does not look like an sbt rem top-level directory and the "new" command was not given. -if not defined sbt_args_sbt_create if not defined sbt_args_print_version if not defined sbt_args_print_sbt_version if not defined sbt_args_print_sbt_script_version if not defined shutdownall if not exist build.sbt ( +if not defined sbt_args_allow_empty if not defined sbt_args_print_version if not defined sbt_args_print_sbt_version if not defined sbt_args_print_sbt_script_version if not defined shutdownall if not exist build.sbt ( if not exist project\ ( if not defined sbt_new ( - echo [warn] Neither build.sbt nor a 'project' directory in the current directory: "%CD%" - setlocal -:confirm - echo c^) continue - echo q^) quit - - set /P reply=^? - if /I "!reply!" == "c" ( - goto confirm_end - ) else if /I "!reply!" == "q" ( - exit /B 1 - ) - - goto confirm -:confirm_end - endlocal + echo [error] Neither build.sbt nor a 'project' directory in the current directory: "%CD%" + echo [error] run 'sbt new', touch build.sbt, or run 'sbt --allow-empty'. + goto error ) ) ) diff --git a/launcher-package/src/universal/conf/sbtopts b/launcher-package/src/universal/conf/sbtopts index c6f4e7bec2..5990223b7c 100644 --- a/launcher-package/src/universal/conf/sbtopts +++ b/launcher-package/src/universal/conf/sbtopts @@ -9,7 +9,7 @@ # Starts sbt even if the current directory contains no sbt project. # --sbt-create +#--allow-empty # Path to global settings/plugins directory (default: ~/.sbt) # @@ -31,11 +31,11 @@ # #-no-share -# Put SBT in offline mode. +# Put sbt in offline mode. # #-offline -# Sets the SBT version to use. +# Sets the sbt version to use. #-sbt-version 0.11.3 # Scala version (default: latest release) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index b8c329dd8b..942fccd555 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -265,6 +265,7 @@ object Defaults extends BuildCommon { csrLogger := LMCoursier.coursierLoggerTask.value, csrMavenProfiles :== Set.empty, csrReconciliations :== LMCoursier.relaxedForAllModules, + csrMavenDependencyOverride :== false, csrSameVersions := Seq( ScalaArtifacts.Artifacts.map(a => InclExclRule(scalaOrganization.value, a)).toSet ) diff --git a/main/src/main/scala/sbt/Keys.scala b/main/src/main/scala/sbt/Keys.scala index fb428c33b0..9349773d7f 100644 --- a/main/src/main/scala/sbt/Keys.scala +++ b/main/src/main/scala/sbt/Keys.scala @@ -454,6 +454,7 @@ object Keys { val csrPublications = taskKey[Seq[(lmcoursier.definitions.Configuration, lmcoursier.definitions.Publication)]]("") val csrReconciliations = settingKey[Seq[(ModuleMatchers, Reconciliation)]]("Strategy to reconcile version conflicts.") val csrSameVersions = settingKey[Seq[Set[InclExclRule]]]("Modules to keep at the same version.") + val csrMavenDependencyOverride = settingKey[Boolean]("Enables Maven dependency override (bill of materials) support") val internalConfigurationMap = settingKey[Configuration => Configuration]("Maps configurations to the actual configuration used to define the classpath.").withRank(CSetting) val classpathConfiguration = taskKey[Configuration]("The configuration used to define the classpath.").withRank(CTask) diff --git a/main/src/main/scala/sbt/coursierint/LMCoursier.scala b/main/src/main/scala/sbt/coursierint/LMCoursier.scala index 84ed5339d4..fd7ebb5463 100644 --- a/main/src/main/scala/sbt/coursierint/LMCoursier.scala +++ b/main/src/main/scala/sbt/coursierint/LMCoursier.scala @@ -121,6 +121,7 @@ object LMCoursier { depsOverrides, None, Nil, + None, log ) @@ -172,6 +173,60 @@ object LMCoursier { depsOverrides, updateConfig, Nil, + None, + log + ) + + // For binary compatibility / MiMa + def coursierConfiguration( + rs: Seq[Resolver], + interProjectDependencies: Seq[CProject], + extraProjects: Seq[CProject], + fallbackDeps: Seq[FallbackDependency], + appConfig: AppConfiguration, + classifiers: Option[Seq[Classifier]], + profiles: Set[String], + scalaOrg: String, + scalaVer: String, + scalaBinaryVer: String, + autoScalaLib: Boolean, + scalaModInfo: Option[ScalaModuleInfo], + excludeDeps: Seq[InclExclRule], + credentials: Seq[Credentials], + createLogger: Option[CacheLogger], + cacheDirectory: File, + reconciliation: Seq[(ModuleMatchers, Reconciliation)], + ivyHome: Option[File], + strict: Option[CStrict], + depsOverrides: Seq[ModuleID], + updateConfig: Option[UpdateConfiguration], + sameVersions: Seq[Set[InclExclRule]], + log: Logger + ): CoursierConfiguration = + coursierConfiguration( + rs, + interProjectDependencies, + extraProjects, + fallbackDeps, + appConfig, + classifiers, + profiles, + scalaOrg, + scalaVer, + scalaBinaryVer, + autoScalaLib, + scalaModInfo, + excludeDeps, + credentials, + createLogger, + cacheDirectory, + reconciliation, + ivyHome, + strict, + depsOverrides, + updateConfig, + sameVersions, + None, log ) @@ -198,6 +253,7 @@ object LMCoursier { depsOverrides: Seq[ModuleID], updateConfig: Option[UpdateConfiguration], sameVersions: Seq[Set[InclExclRule]], + enableDependencyOverrides: Option[Boolean], log: Logger ): CoursierConfiguration = { val coursierExcludeDeps = Inputs @@ -252,6 +308,7 @@ object LMCoursier { .withForceVersions(userForceVersions.toVector) .withMissingOk(missingOk) .withSameVersions(sameVersions) + .withEnableDependencyOverrides(enableDependencyOverrides) } def coursierConfigurationTask: Def.Initialize[Task[CoursierConfiguration]] = Def.task { @@ -279,6 +336,7 @@ object LMCoursier { dependencyOverrides.value, Some(updateConfiguration.value), csrSameVersions.value, + Some(csrMavenDependencyOverride.value), streams.value.log ) } @@ -308,6 +366,7 @@ object LMCoursier { dependencyOverrides.value, Some(updateConfiguration.value), csrSameVersions.value, + Some(csrMavenDependencyOverride.value), streams.value.log ) } @@ -337,6 +396,7 @@ object LMCoursier { dependencyOverrides.value, Some(updateConfiguration.value), csrSameVersions.value, + Some(csrMavenDependencyOverride.value), streams.value.log ) } @@ -366,6 +426,7 @@ object LMCoursier { dependencyOverrides.value, Some(updateConfiguration.value), csrSameVersions.value, + Some(csrMavenDependencyOverride.value), streams.value.log ) } diff --git a/main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala b/main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala index 51e60575b5..4aedac6aa8 100644 --- a/main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala +++ b/main/src/main/scala/sbt/plugins/Giter8TemplatePlugin.scala @@ -27,7 +27,7 @@ object Giter8TemplatePlugin extends AutoPlugin { ModuleID( "org.scala-sbt.sbt-giter8-resolver", "sbt-giter8-resolver", - "0.16.2" + "0.17.0" ) cross CrossVersion.binary, "sbtgiter8resolver.Giter8TemplateResolver" ) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index d34375260b..9e4b893be7 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -12,10 +12,10 @@ object Dependencies { sys.env.get("BUILD_VERSION") orElse sys.props.get("sbt.build.version") // sbt modules - private val ioVersion = nightlyVersion.getOrElse("1.10.2") + private val ioVersion = nightlyVersion.getOrElse("1.10.3") private val lmVersion = sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.10.3") - val zincVersion = nightlyVersion.getOrElse("1.10.5") + val zincVersion = nightlyVersion.getOrElse("1.10.7") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion @@ -77,23 +77,20 @@ object Dependencies { def addSbtZincCompile = addSbtModule(sbtZincPath, "zincCompile", zincCompile) def addSbtZincCompileCore = addSbtModule(sbtZincPath, "zincCompileCore", zincCompileCore) - val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.1.6" + val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.1.7" def sjsonNew(n: String) = Def.setting("com.eed3si9n" %% n % "0.10.1") // contrabandSjsonNewVersion.value val sjsonNewScalaJson = sjsonNew("sjson-new-scalajson") val sjsonNewMurmurhash = sjsonNew("sjson-new-murmurhash") - // JLine 3 version must be coordinated together with JAnsi version - // and the JLine 2 fork version, which uses the same JAnsi - val jline = "org.scala-sbt.jline" % "jline" % "2.14.7-sbt-9c3b6aca11c57e339441442bbf58e550cdfecb79" + val jline = "org.scala-sbt.jline" % "jline" % "2.14.7-sbt-9a88bc413e2b34a4580c001c654d1a7f4f65bf18" val jline3Version = "3.27.1" val jline3Terminal = "org.jline" % "jline-terminal" % jline3Version val jline3JNI = "org.jline" % "jline-terminal-jni" % jline3Version val jline3Native = "org.jline" % "jline-native" % jline3Version val jline3Reader = "org.jline" % "jline-reader" % jline3Version val jline3Builtins = "org.jline" % "jline-builtins" % jline3Version - val jansi = "org.fusesource.jansi" % "jansi" % "2.4.1" val scalatest = "org.scalatest" %% "scalatest" % "3.2.10" val scalacheck = "org.scalacheck" %% "scalacheck" % "1.15.4" val junit = "junit" % "junit" % "4.13.1" diff --git a/project/build.properties b/project/build.properties index db1723b086..e88a0d817d 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.5 +sbt.version=1.10.6 diff --git a/sbt b/sbt index e256902113..d178f16c3f 100755 --- a/sbt +++ b/sbt @@ -1,7 +1,7 @@ #!/usr/bin/env bash set +e -declare builtin_sbt_version="1.10.6" +declare builtin_sbt_version="1.10.7" declare -a residual_args declare -a java_args declare -a scalac_args @@ -25,6 +25,7 @@ declare use_sbtn= declare no_server= declare sbtn_command="$SBTN_CMD" declare sbtn_version="1.10.5" +declare use_colors=1 ### ------------------------------- ### ### Helper methods for BASH scripts ### @@ -104,6 +105,15 @@ declare -r sbt_home="$(dirname "$sbt_bin_dir")" echoerr () { echo 1>&2 "$@" } +RED='\033[0;31m' +NC='\033[0m' # No Color +echoerr_error () { + if [[ $use_colors == "1" ]]; then + echoerr -e "[${RED}error${NC}] $@" + else + echoerr "[error] $@" + fi +} vlog () { [[ $sbt_verbose || $sbt_debug ]] && echoerr "$@" } @@ -483,6 +493,21 @@ copyRt() { fi } +# Confirm a user's intent if the current directory does not look like an sbt +# top-level directory and neither the --allow-empty option nor the "new" command was given. +checkWorkingDirectory() { + if [[ ! -n "$allow_empty" ]]; then + [[ -f ./build.sbt || -d ./project || -n "$sbt_new" ]] || { + echoerr_error "Neither build.sbt nor a 'project' directory in the current directory: $(pwd)" + echoerr_error "run 'sbt new', touch build.sbt, or run 'sbt --allow-empty'." + echoerr_error "" + echoerr_error "To opt out of this check, create ${config_home}/sbtopts with:" + echoerr_error "--allow-empty" + exit 1 + } + fi +} + run() { # Copy preloaded repo to user's preloaded directory syncPreloaded @@ -519,6 +544,7 @@ run() { done echo "shutdown ${#sbt_processes[@]} sbt processes" else + checkWorkingDirectory # run sbt execRunner "$java_cmd" \ "${java_args[@]}" \ @@ -543,7 +569,10 @@ declare -r sbt_opts_file=".sbtopts" declare -r build_props_file="$(pwd)/project/build.properties" declare -r etc_sbt_opts_file="/etc/sbt/sbtopts" # this allows /etc/sbt/sbtopts location to be changed -declare -r etc_file="${SBT_ETC_FILE:-$etc_sbt_opts_file}" +declare machine_sbt_opts_file="${etc_sbt_opts_file}" +declare config_home="${XDG_CONFIG_HOME:-$HOME/.config}/sbt" +[[ -f "${config_home}/sbtopts" ]] && machine_sbt_opts_file="${config_home}/sbtopts" +[[ -f "$SBT_ETC_FILE" ]] && machine_sbt_opts_file="$SBT_ETC_FILE" declare -r dist_sbt_opts_file="${sbt_home}/conf/sbtopts" declare -r win_sbt_opts_file="${sbt_home}/conf/sbtconfig.txt" declare sbt_jar="$(jar_file)" @@ -568,7 +597,7 @@ Usage: `basename "$0"` [options] enable or disable supershell (sbt 1.3 and above) --traces generate Trace Event report on shutdown (sbt 1.3 and above) --timings display task timings report on shutdown - --sbt-create start sbt even if current directory contains no sbt project + --allow-empty start sbt even if current directory contains no sbt project --sbt-dir path to global settings/plugins directory (default: ~/.sbt) --sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11 series) --sbt-cache path to global cache directory (default: operating system specific) @@ -607,7 +636,7 @@ process_my_args () { case "$1" in -batch|--batch) exec - -sbt-create|--sbt-create) sbt_create=true && shift ;; + -allow-empty|--allow-empty|-sbt-create|--sbt-create) allow_empty=true && shift ;; new) sbt_new=true && addResidual "$1" && shift ;; @@ -617,23 +646,6 @@ process_my_args () { # Now, ensure sbt version is used. [[ "${sbt_version}XXX" != "XXX" ]] && addJava "-Dsbt.version=$sbt_version" - - # Confirm a user's intent if the current directory does not look like an sbt - # top-level directory and neither the -sbt-create option nor the "new" - # command was given. - [[ -f ./build.sbt || -d ./project || -n "$sbt_create" || -n "$sbt_new" ]] || { - echo "[warn] Neither build.sbt nor a 'project' directory in the current directory: $(pwd)" - while true; do - echo 'c) continue' - echo 'q) quit' - - read -p '? ' || exit 1 - case "$REPLY" in - c|C) break ;; - q|Q) exit 1 ;; - esac - done - } } ## map over argument array. this is used to process both command line arguments and SBT_OPTS @@ -694,6 +706,7 @@ process_args () { export PATH="$2/bin:$PATH" && shift 2 ;; + -Dsbt.color=never|-Dsbt.log.noformat=true) addJava "$1" && use_colors=0 && shift ;; "-D*"|-D*) addJava "$1" && shift ;; -J*) addJava "${1:2}" && shift ;; *) addResidual "$1" && shift ;; @@ -785,11 +798,13 @@ runNativeClient() { original_args=("$@") -# Here we pull in the default settings configuration. -[[ -f "$dist_sbt_opts_file" ]] && set -- $(loadConfigFile "$dist_sbt_opts_file") "$@" - -# Here we pull in the global settings configuration. -[[ -f "$etc_file" ]] && set -- $(loadConfigFile "$etc_file") "$@" +# Pull in the machine-wide settings configuration. +if [[ -f "$machine_sbt_opts_file" ]]; then + set -- $(loadConfigFile "$machine_sbt_opts_file") "$@" +else + # Otherwise pull in the default settings configuration. + [[ -f "$dist_sbt_opts_file" ]] && set -- $(loadConfigFile "$dist_sbt_opts_file") "$@" +fi # Pull in the project-level config file, if it exists. [[ -f "$sbt_opts_file" ]] && set -- $(loadConfigFile "$sbt_opts_file") "$@" diff --git a/sbt-app/src/sbt-test/actions/add-alias/test b/sbt-app/src/sbt-test/actions/add-alias/test index 0269ab4f88..9a7db37822 100644 --- a/sbt-app/src/sbt-test/actions/add-alias/test +++ b/sbt-app/src/sbt-test/actions/add-alias/test @@ -2,3 +2,5 @@ -> demo-failure > +z > z + +$ absent /tmp/non-existent diff --git a/sbt-app/src/sbt-test/actions/clean-managed/test b/sbt-app/src/sbt-test/actions/clean-managed/test index f6fd6ce8f8..5023111888 100644 --- a/sbt-app/src/sbt-test/actions/clean-managed/test +++ b/sbt-app/src/sbt-test/actions/clean-managed/test @@ -1,6 +1,6 @@ > compile -$ exists target/scala-2.12/src_managed/foo.txt target/scala-2.12/src_managed/bar.txt +$ exists target/**/src_managed/foo.txt target/**/src_managed/bar.txt > clean -$ absent target/scala-2.12/src_managed/foo.txt -$ exists target/scala-2.12/src_managed/bar.txt +$ absent target/**/src_managed/foo.txt +$ exists target/**/src_managed/bar.txt diff --git a/sbt-app/src/sbt-test/actions/compile-clean/test b/sbt-app/src/sbt-test/actions/compile-clean/test index 2e805ffd03..7d983f7cae 100644 --- a/sbt-app/src/sbt-test/actions/compile-clean/test +++ b/sbt-app/src/sbt-test/actions/compile-clean/test @@ -1,22 +1,22 @@ $ touch target/cant-touch-this > Test/compile -$ exists target/scala-2.12/classes/A.class -$ exists target/scala-2.12/test-classes/B.class +$ exists target/**/classes/A.class +$ exists target/**/test-classes/B.class > Test/clean $ exists target/cant-touch-this # it should clean only compile classes -$ exists target/scala-2.12/classes/A.class -$ exists target/scala-2.12/classes/X.class -$ absent target/scala-2.12/test-classes/B.class +$ exists target/**/classes/A.class +$ exists target/**/classes/X.class +$ absent target/**/test-classes/B.class # compiling everything again, but now cleaning only compile classes > Test/compile > Compile/clean $ exists target/cant-touch-this # it should clean only compile classes -$ absent target/scala-2.12/classes/A.class -$ exists target/scala-2.12/test-classes/B.class +$ absent target/**/classes/A.class +$ exists target/**/test-classes/B.class # and X has to be kept, because of the cleanKeepFiles override -$ exists target/scala-2.12/classes/X.class +$ exists target/**/classes/X.class diff --git a/sbt-app/src/sbt-test/actions/task-map/test b/sbt-app/src/sbt-test/actions/task-map/test index 3a88d40a75..a3bec9fa79 100644 --- a/sbt-app/src/sbt-test/actions/task-map/test +++ b/sbt-app/src/sbt-test/actions/task-map/test @@ -1,7 +1,7 @@ > taskB -$ exists target/b -$ exists target/a +$ exists target/**/b +$ exists target/**/a > taskF -$ exists target/e -$ exists target/f +$ exists target/**/e +$ exists target/**/f diff --git a/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt b/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt index fae8cacabd..c05b42e715 100644 --- a/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt +++ b/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt @@ -4,6 +4,7 @@ libraryDependencies ++= Seq( "org.slf4j" % "slf4j-api" % "1.7.2", "ch.qos.logback" % "logback-classic" % "1.0.7" ) +csrMavenDependencyOverride := false TaskKey[Unit]("check") := { val report = updateFull.value diff --git a/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/pending b/sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/test similarity index 100% rename from sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/pending rename to sbt-app/src/sbt-test/dependency-graph/ignoreScalaLibrary/test diff --git a/sbt-app/src/sbt-test/project/scripted13/test b/sbt-app/src/sbt-test/project/scripted13/test index b321a8554c..d40ea3d077 100644 --- a/sbt-app/src/sbt-test/project/scripted13/test +++ b/sbt-app/src/sbt-test/project/scripted13/test @@ -1,6 +1,6 @@ # This tests that this sbt scripted plugin can launch the previous one -> ^^1.10.5 +> ^^1.10.6 $ copy-file changes/A.scala src/sbt-test/a/b/A.scala > scripted