From cd58481811689c676d448c87f2ec17e1f2497929 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Fri, 20 Dec 2024 03:02:26 -0500 Subject: [PATCH] --allow-empty fixes **Problem** 1. Currently users are automatically opted into -create-sbt, somewhat implicitly. 2. When somehow they are not, the check mechanism currently blocks for input. **Solution** 1. Support a new location for sbtopts file under XSG_CONFIG_HOME/sbt 2. Rename -create-sbt to --allow-empty, and don't opt everyone in 3. Exit 1 instead of blocking for input --- .../src/test/scala/RunnerTest.scala | 26 ++++++++ launcher-package/src/universal/bin/sbt.bat | 47 ++++++-------- launcher-package/src/universal/conf/sbtopts | 6 +- sbt | 65 ++++++++++++------- 4 files changed, 88 insertions(+), 56 deletions(-) diff --git a/launcher-package/integration-test/src/test/scala/RunnerTest.scala b/launcher-package/integration-test/src/test/scala/RunnerTest.scala index f3d406502..382b259d7 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 f9d6ce6fd..2bd4dd49e 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 c6f4e7bec..5990223b7 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/sbt b/sbt index e25690211..9a1a4a0b4 100755 --- a/sbt +++ b/sbt @@ -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") "$@"