Skip to content

Commit

Permalink
Updates to options processing.
Browse files Browse the repository at this point in the history
Reworked how args are passed to the jvm and to sbt.
This is a breaking change if you used these features.
I dropped a couple options which were more trouble than
they are worth, and am generally assuming less on
startup. The main thing is that you can tightly control
what args arrive at the jvm and at sbt now.

I also changed some defaults for faster startup; it's too
slow passing extra settings to sbt all the time.

Note that -sbt-opts and -jvm-opts take filename arguments;
I'm using command substitution here.

  % sbt -sbt-opts <(printf "%s\n%s\n" -trace 4) -jvm-opts <(echo -verbose:gc)

results in this command line:

  java -Xmx128m -Dsbt.global.base=/Users/paulp/.sbt/0.12.2 \
    -jar sbt-launch.jar "set every traceLevel := 4" shell

Or the same outcome with environment variables:

  % JVM_OPTS="-verbose:gc" SBT_OPTS="-trace 4" sbt
  • Loading branch information
paulp committed Mar 1, 2013
1 parent 338fa32 commit 34c7370
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 99 deletions.
34 changes: 17 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,12 @@ Current -help output:
-v | -verbose this runner is chattier
-d | -debug set sbt log level to Debug
-q | -quiet set sbt log level to Error
-trace <level> display stack traces with a max of <level> frames (default: 15)
-trace <level> display stack traces with a max of <level> frames (default: -1, traces suppressed)
-no-colors disable ANSI color codes
-sbt-create start sbt even if current directory contains no sbt project
-sbt-dir <path> path to global settings/plugins directory (default: ~/.sbt/<version>)
-sbt-boot <path> path to shared boot directory (default: ~/.sbt/boot in 0.11+)
-ivy <path> path to local Ivy repository (default: ~/.ivy2)
-mem <integer> set memory options (default: 1536, which is
-Xms1536m -Xmx1536m -XX:MaxPermSize=384m -XX:ReservedCodeCacheSize=192m )
-no-share use all local caches; no sharing
-offline put sbt in offline mode
-jvm-debug <port> Turn on JVM debugging, open at the given port.
Expand All @@ -87,25 +85,27 @@ Current -help output:

# scala version (default: as chosen by sbt)
-28 use 2.8.2
-29 use 2.9.2
-210 use 2.10.0-RC2
-29 use 2.9.3
-210 use 2.10.0
-scala-home <path> use the scala build at the specified directory
-scala-version <version> use the specified version of scala
-binary-version <version> use the specified scala version when searching for dependencies

# java version (default: java from PATH, currently java version "1.7.0_06")
# java version (default: java from PATH, currently java version "1.7.0_15")
-java-home <path> alternate JAVA_HOME

# jvm options and output control
JAVA_OPTS environment variable holding jvm args, if unset uses "-Dfile.encoding=UTF8"
SBT_OPTS environment variable holding jvm args, if unset uses "-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC"
.jvmopts if file is in sbt root, it is prepended to the args given to the jvm
.sbtopts if file is in sbt root, it is prepended to the args given to **sbt**
-Dkey=val pass -Dkey=val directly to the jvm
-J-X pass option -X directly to the jvm (-J is stripped)
-S-X add -X to sbt's scalacOptions (-S is stripped)

In the case of duplicated or conflicting options, the order above
shows precedence: JAVA_OPTS lowest, command line options highest.
# passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution
# The default set is used if JVM_OPTS is unset and no -jvm-opts file is found
<default> -Dfile.encoding=UTF8 -XX:MaxPermSize=256m -Xms512m -Xmx1g -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC
JVM_OPTS environment variable holding jvm args
-jvm-opts <path> file containing jvm args (if not given, .jvmopts in project root is used if present)
-Dkey=val pass -Dkey=val directly to the jvm
-J-X pass option -X directly to the jvm (-J is stripped)

# passing options to sbt, OR to this runner
SBT_OPTS environment variable holding sbt args
-sbt-opts <path> file containing sbt args (if not given, .sbtopts in project root is used if present)
-S-X add -X to sbt's scalacOptions (-S is stripped)

## SBT Extra plugin

Expand Down
157 changes: 75 additions & 82 deletions sbt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
declare -r sbt_release_version=0.12.2
declare -r sbt_snapshot_version=0.13.0-SNAPSHOT

unset sbt_jar sbt_dir sbt_create sbt_snapshot sbt_launch_dir
unset scala_version java_home sbt_explicit_version
unset verbose debug quiet noshare trace_level log_level
declare sbt_jar sbt_dir sbt_create sbt_snapshot sbt_launch_dir
declare scala_version java_home sbt_explicit_version
declare verbose debug quiet noshare trace_level log_level

for arg in "$@"; do
case $arg in
Expand All @@ -19,7 +19,7 @@ for arg in "$@"; do
done

build_props_sbt () {
if [[ -f project/build.properties ]]; then
if [[ -r project/build.properties ]]; then
versionLine=$(grep ^sbt.version project/build.properties)
versionString=${versionLine##sbt.version=}
echo "$versionString"
Expand All @@ -32,7 +32,7 @@ update_build_props_sbt () {

if [[ $ver == $old ]]; then
return
elif [[ -f project/build.properties ]]; then
elif [[ -r project/build.properties ]]; then
perl -pi -e "s/^sbt\.version=.*\$/sbt.version=${ver}/" project/build.properties
grep -q '^sbt.version=' project/build.properties || echo "sbt.version=${ver}" >> project/build.properties

Expand Down Expand Up @@ -80,18 +80,6 @@ get_script_path () {
fi
}

# a ham-fisted attempt to move some memory settings in concert
# so they need not be dicked around with individually.
get_mem_opts () {
local mem=${1:-1536}
local perm=$(( $mem / 4 ))
(( $perm > 256 )) || perm=256
(( $perm < 1024 )) || perm=1024
local codecache=$(( $perm / 2 ))

echo "-Xms${mem}m -Xmx${mem}m -XX:MaxPermSize=${perm}m -XX:ReservedCodeCacheSize=${codecache}m"
}

die() {
echo "Aborting: $@"
exit 1
Expand All @@ -105,15 +93,10 @@ make_url () {
echo "http://typesafe.artifactoryonline.com/typesafe/ivy-$category/$groupid/sbt-launch/$version/sbt-launch.jar"
}

declare -r default_jvm_opts="-Dfile.encoding=UTF8"
declare -r default_sbt_opts="-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC"
declare -r default_sbt_mem=1536
declare -r default_trace_level=15
declare -r default_jvm_opts="-Dfile.encoding=UTF8 -XX:MaxPermSize=256m -Xms512m -Xmx1g -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC"
declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy"
declare -r sbt_opts_file=".sbtopts"
declare -r jvm_opts_file=".jvmopts"
declare -r latest_28="2.8.2"
declare -r latest_29="2.9.2"
declare -r latest_29="2.9.3"
declare -r latest_210="2.10.0"

declare -r script_path=$(get_script_path "$BASH_SOURCE")
Expand All @@ -124,21 +107,24 @@ declare -r script_name="$(basename $script_path)"
declare java_cmd=java
declare sbt_launch_dir="$script_dir/.lib"
declare sbt_universal_launcher="$script_dir/lib/sbt-launch.jar"
declare sbt_mem=$default_sbt_mem
declare sbt_jar=$sbt_universal_launcher
declare trace_level=$default_trace_level
declare sbt_opts_file=.sbtopts
declare jvm_opts_file=.jvmopts

# pull -J and -D options to give to java.
declare -a residual_args
declare -a java_args
declare -a scalac_args
declare -a sbt_commands

# args to jvm/sbt via files or environment variables
declare -a extra_jvm_opts extra_sbt_opts

# if set, use JAVA_HOME over java found in path
[[ -e "$JAVA_HOME/bin/java" ]] && java_cmd="$JAVA_HOME/bin/java"

build_props_scala () {
if [[ -f project/build.properties ]]; then
if [[ -r project/build.properties ]]; then
versionLine=$(grep ^build.scala.versions project/build.properties)
versionString=${versionLine##build.scala.versions=}
echo ${versionString%% .*}
Expand All @@ -149,10 +135,12 @@ execRunner () {
# print the arguments one to a line, quoting any containing spaces
[[ $verbose || $debug ]] && echo "# Executing command line:" && {
for arg; do
if printf "%s\n" "$arg" | grep -q ' '; then
printf "\"%s\"\n" "$arg"
else
printf "%s\n" "$arg"
if [[ -n "$arg" ]]; then
if printf "%s\n" "$arg" | grep -q ' '; then
printf "\"%s\"\n" "$arg"
else
printf "%s\n" "$arg"
fi
fi
done
echo ""
Expand Down Expand Up @@ -225,14 +213,14 @@ download_url () {
elif which wget >/dev/null; then
wget --quiet -O "$jar" "$url"
fi
} && [[ -f "$jar" ]]
} && [[ -r "$jar" ]]
}

acquire_sbt_jar () {
sbt_url="$(jar_url)"
sbt_jar="$(jar_file $(sbt_version))"

[[ -f "$sbt_jar" ]] || download_url "$sbt_url" "$sbt_jar"
[[ -r "$sbt_jar" ]] || download_url "$sbt_url" "$sbt_jar"
}

usage () {
Expand All @@ -243,14 +231,12 @@ Usage: $script_name [options]
-v | -verbose this runner is chattier
-d | -debug set sbt log level to Debug
-q | -quiet set sbt log level to Error
-trace <level> display stack traces with a max of <level> frames (default: $default_trace_level)
-trace <level> display stack traces with a max of <level> frames (default: -1, traces suppressed)
-no-colors disable ANSI color codes
-sbt-create start sbt even if current directory contains no sbt project
-sbt-dir <path> path to global settings/plugins directory (default: ~/.sbt/<version>)
-sbt-boot <path> path to shared boot directory (default: ~/.sbt/boot in 0.11+)
-ivy <path> path to local Ivy repository (default: ~/.ivy2)
-mem <integer> set memory options (default: $sbt_mem, which is
$(get_mem_opts $sbt_mem) )
-no-share use all local caches; no sharing
-offline put sbt in offline mode
-jvm-debug <port> Turn on JVM debugging, open at the given port.
Expand All @@ -276,17 +262,18 @@ Usage: $script_name [options]
# java version (default: java from PATH, currently $(java -version |& grep version))
-java-home <path> alternate JAVA_HOME
# jvm options and output control
JAVA_OPTS environment variable holding jvm args, if unset uses "$default_jvm_opts"
SBT_OPTS environment variable holding jvm args, if unset uses "$default_sbt_opts"
.jvmopts if file is in sbt root, it is prepended to the args given to the jvm
.sbtopts if file is in sbt root, it is prepended to the args given to **sbt**
-Dkey=val pass -Dkey=val directly to the jvm
-J-X pass option -X directly to the jvm (-J is stripped)
-S-X add -X to sbt's scalacOptions (-S is stripped)
In the case of duplicated or conflicting options, the order above
shows precedence: JAVA_OPTS lowest, command line options highest.
# passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution
# The default set is used if JVM_OPTS is unset and no -jvm-opts file is found
<default> $default_jvm_opts
JVM_OPTS environment variable holding jvm args
-jvm-opts <path> file containing jvm args (if not given, .jvmopts in project root is used if present)
-Dkey=val pass -Dkey=val directly to the jvm
-J-X pass option -X directly to the jvm (-J is stripped)
# passing options to sbt, OR to this runner
SBT_OPTS environment variable holding sbt args
-sbt-opts <path> file containing sbt args (if not given, .sbtopts in project root is used if present)
-S-X add -X to sbt's scalacOptions (-S is stripped)
EOM
}

Expand Down Expand Up @@ -319,13 +306,6 @@ setScalaVersion () {
fi
}

get_jvm_opts () {
# echo "${JAVA_OPTS:-$default_jvm_opts}"
# echo "${SBT_OPTS:-$default_sbt_opts}"

[[ -f "$jvm_opts_file" ]] && cat "$jvm_opts_file"
}

process_args ()
{
require_arg () {
Expand All @@ -346,7 +326,6 @@ process_args ()

-trace) require_arg integer "$1" "$2" && trace_level=$2 && shift 2 ;;
-ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;;
-mem) require_arg integer "$1" "$2" && sbt_mem="$2" && shift 2 ;;
-no-colors) addJava "-Dsbt.log.noformat=true" && shift ;;
-no-share) noshare=true && shift ;;
-sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;;
Expand All @@ -366,6 +345,8 @@ process_args ()
-binary-version) require_arg version "$1" "$2" && addSbt "set scalaBinaryVersion in ThisBuild := \"$2\"" && shift 2 ;;
-scala-home) require_arg path "$1" "$2" && addSbt "set every scalaHome := Some(file(\"$2\"))" && shift 2 ;;
-java-home) require_arg path "$1" "$2" && java_cmd="$2/bin/java" && shift 2 ;;
-sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;;
-jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;;

-D*) addJava "$1" && shift ;;
-J*) addJava "${1:2}" && shift ;;
Expand All @@ -379,28 +360,31 @@ process_args ()
done
}

# if .sbtopts exists, prepend its contents to $@ so it can be processed by this runner
[[ -f "$sbt_opts_file" ]] && {
sbtargs=()
while IFS= read -r arg; do
sbtargs=( "${sbtargs[@]}" "$arg" )
done <"$sbt_opts_file"

set -- "${sbtargs[@]}" "$@"
}

# process the combined args, then reset "$@" to the residuals
# process the direct command line arguments
process_args "$@"

# if there are file/environment sbt_opts, process again so we
# can supply args to this runner
if [[ -r "$sbt_opts_file" ]]; then
readarray -t extra_sbt_opts < "$sbt_opts_file"
elif [[ -n "$SBT_OPTS" ]]; then
extra_sbt_opts=( $SBT_OPTS )
fi

[[ -n $extra_sbt_opts ]] && process_args "${extra_sbt_opts[@]}"

# reset "$@" to the residual args
set -- "${residual_args[@]}"
argumentCount=$#

# set sbt version specific options
case $(sbt_version) in
0.7.*) ;;
0.10.*) ;;
0.11.*) ;;
*) addSbt "set every traceLevel := $trace_level" ;;
esac
# only exists in 0.12+
setTraceLevel() {
case $(sbt_version) in
0.{7,10,11}.*) echoerr "Cannot set trace level in sbt version $(sbt_version)" ;;
*) addSbt "set every traceLevel := $trace_level" ;;
esac
}

# set scalacOptions if we were given any -S opts
[[ ${#scalac_args[@]} -eq 0 ]] || addSbt "set scalacOptions in ThisBuild += \"${scalac_args[@]}\""
Expand All @@ -415,7 +399,7 @@ echoerr "Detected sbt version $(sbt_version)"
(( $argumentCount > 0 )) || echo "Starting $script_name: invoke with -help for other options"

# verify this is an sbt dir or -create was given
[[ -f ./build.sbt || -d ./project || -n "$sbt_create" ]] || {
[[ -r ./build.sbt || -d ./project || -n "$sbt_create" ]] || {
cat <<EOM
$(pwd) doesn't appear to be an sbt project.
If you want to start sbt anyway, run:
Expand All @@ -426,10 +410,10 @@ EOM
}

# pick up completion if present; todo
[[ -f .sbt_completion.sh ]] && source .sbt_completion.sh
[[ -r .sbt_completion.sh ]] && source .sbt_completion.sh

# no jar? download it.
[[ -f "$sbt_jar" ]] || acquire_sbt_jar || {
[[ -r "$sbt_jar" ]] || acquire_sbt_jar || {
# still no jar? uh-oh.
echo "Download failed. Obtain the jar manually and place it at $sbt_jar"
exit 1
Expand All @@ -445,19 +429,28 @@ else
addJava "-Dsbt.global.base=$sbt_dir"
fi

if [[ -r "$jvm_opts_file" ]]; then
readarray -t extra_jvm_opts < "$jvm_opts_file"
elif [[ -n "$JVM_OPTS" ]]; then
extra_jvm_opts=( $JVM_OPTS )
else
extra_jvm_opts=( $default_jvm_opts )
fi

# since sbt 0.7 doesn't understand iflast
(( ${#residual_args[@]} == 0 )) && residual_args=( "shell" )
[[ ${#residual_args[@]} -eq 0 ]] && residual_args=( "shell" )

# -shell \
# "set every traceLevel := $trace_level" \
[[ -n $log_level ]] && logLevalArg="set logLevel in Global := Level.$log_level"
# traceLevel is 0.12+
[[ -n $trace_level ]] && setTraceLevel

[[ -n $log_level ]] && [[ $log_level != Info ]] && logLevalArg="set logLevel in Global := Level.$log_level"

# run sbt
execRunner "$java_cmd" \
$(get_mem_opts $sbt_mem) \
$(get_jvm_opts) \
${java_args[@]} \
"${extra_jvm_opts[@]}" \
"${java_args[@]}" \
-jar "$sbt_jar" \
"$logLevalArg" \
"${sbt_commands[@]}" \
"${residual_args[@]}"

0 comments on commit 34c7370

Please sign in to comment.