Skip to content

Fixes for various problems related to scripting. #11489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/repl/JLineTerminal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ final class JLineTerminal extends java.io.Closeable {

private val terminal =
TerminalBuilder.builder()
.dumb(false) // fail early if not able to create a terminal
.dumb(dumbTerminal) // fail early if not able to create a terminal
.build()
private val history = new DefaultHistory
def dumbTerminal = Option(System.getenv("TERM")) == Some("dumb")

private def blue(str: String)(using Context) =
if (ctx.settings.color.value != "never") Console.BLUE + str + Console.RESET
Expand Down
17 changes: 7 additions & 10 deletions compiler/src/dotty/tools/scripting/Main.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dotty.tools.scripting

import java.io.File
import java.nio.file.Path
import java.nio.file.{Path, Paths}
import dotty.tools.dotc.config.Properties.isWin

/** Main entry point to the Scripting execution engine */
Expand Down Expand Up @@ -60,7 +60,7 @@ object Main:
def scriptBasename = scriptFile.getName.takeWhile(_!='.')
val jarPath = s"$jarTargetDir/$scriptBasename.jar"

val cpPaths = runtimeClasspath.split(pathsep).map(_.absPath)
val cpPaths = runtimeClasspath.split(pathsep).map(_.toUrl)

import java.util.jar.Attributes.Name
val cpString:String = cpPaths.distinct.mkString(" ")
Expand All @@ -80,29 +80,26 @@ object Main:

def pathsep = sys.props("path.separator")


extension(file: File){
def norm: String = file.toString.norm
}

extension(path: String) {
// Normalize path separator, convert relative path to absolute
def norm: String =
path.replace('\\', '/') match {
case s if s.secondChar == ":" => s.drop(2)
case s if s.secondChar == ":" => s
case s if s.startsWith("./") => s.drop(2)
case s => s
}

// convert to absolute path relative to cwd.
def absPath: String = norm match
case str if str.isAbsolute => norm
case _ => s"/${sys.props("user.dir").norm}/$norm"
case _ => Paths.get(userDir,norm).toString.norm

def absFile: File = File(path.absPath)
def toUrl: String = Paths.get(absPath).toUri.toURL.toString

// Treat norm paths with a leading '/' as absolute.
// Windows java.io.File#isAbsolute treats them as relative.
def isAbsolute = path.norm.startsWith("/") || (isWin && path.secondChar == ":")
def secondChar: String = path.take(2).drop(1).mkString("")
}

lazy val userDir = sys.props("user.dir").norm
20 changes: 20 additions & 0 deletions compiler/test-resources/scripting/hashBang.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env scala
# comment
STUFF=nada
!#

def main(args: Array[String]): Unit =
System.err.printf("mainClassFromStack: %s\n",mainFromStack)
assert(mainFromStack.contains("hashBang"),s"fromStack[$mainFromStack]")

lazy val mainFromStack:String = {
val result = new java.io.StringWriter()
new RuntimeException("stack").printStackTrace(new java.io.PrintWriter(result))
val stack = result.toString.split("[\r\n]+").toList
//for( s <- stack ){ System.err.printf("[%s]\n",s) }
stack.filter { str => str.contains(".main(") }.map {
_.replaceAll(".*[(]","").
replaceAll("\\.main\\(.*","").
replaceAll(".scala.*","")
}.distinct.take(1).mkString("")
}
22 changes: 22 additions & 0 deletions compiler/test-resources/scripting/mainClassOnStack.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env scala
export STUFF=nada
#lots of other stuff that isn't valid scala
!#
object Zoo {
def main(args: Array[String]): Unit =
printf("script.name: %s\n",sys.props("script.name"))
printf("mainClassFromStack: %s\n",mainFromStack)
assert(mainFromStack == "Zoo",s"fromStack[$mainFromStack]")

lazy val mainFromStack:String = {
val result = new java.io.StringWriter()
new RuntimeException("stack").printStackTrace(new java.io.PrintWriter(result))
val stack = result.toString.split("[\r\n]+").toList
// for( s <- stack ){ System.err.printf("[%s]\n",s) }
val shortStack = stack.filter { str => str.contains(".main(") && ! str.contains("$") }.map {
_.replaceAll("[.].*","").replaceAll("\\s+at\\s+","")
}
// for( s <- shortStack ){ System.err.printf("[%s]\n",s) }
shortStack.take(1).mkString("|")
}
}
9 changes: 9 additions & 0 deletions compiler/test-resources/scripting/scriptName.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env scala

def main(args: Array[String]): Unit =
val name = Option(sys.props("script.name")) match {
case None => printf("no script.name property is defined\n")
case Some(name) =>
printf("script.name: %s\n",name)
assert(name == "scriptName.scala")
}
64 changes: 49 additions & 15 deletions dist/bin/common
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,39 @@
# * Credits: This script is based on the script generated by sbt-pack.
# *--------------------------------------------------------------------------*/

# save terminal settings
saved_stty=$(stty -g 2>/dev/null)
# clear on error so we don't later try to restore them
if [[ ! $? ]]; then
saved_stty=""
fi

# restore stty settings (echo in particular)
function restoreSttySettings() {
stty $saved_stty
saved_stty=""
}

scala_exit_status=127
function onExit() {
[[ "$saved_stty" != "" ]] && restoreSttySettings
exit $scala_exit_status
}

# to reenable echo if we are interrupted before completing.
trap onExit INT TERM

cygwin=false
mingw=false
msys=false
darwin=false
case "`uname`" in
CYGWIN*) cygwin=true
;;
MINGW*) mingw=true
;;
MSYS*) msys=true
;;
Darwin*) darwin=true
if [ -z "$JAVA_VERSION" ] ; then
JAVA_VERSION="CurrentJDK"
Expand All @@ -25,6 +50,18 @@ case "`uname`" in
;;
esac

unset CYGPATHCMD
if [[ ($cygwin||$mingw||$msys) ]]; then
# cygpath is used by various windows shells: cygwin, git-sdk, gitbash, msys, etc.
CYGPATHCMD=`which cygpath 2>/dev/null`
case "$TERM" in
rxvt* | xterm* | cygwin*)
stty -icanon min 1 -echo
SCALA_OPTS="$SCALA_OPTS -Djline.terminal=unix"
;;
esac
fi

# Resolve JAVA_HOME from javac command path
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
Expand All @@ -41,9 +78,8 @@ if [ -z "$JAVA_HOME" ]; then
fi
fi


if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -z "${JAVACMD-}" ] ; then
if [ -n "${JAVA_HOME-}" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
Expand All @@ -69,18 +105,16 @@ CLASSPATH_SUFFIX=""
# Path separator used in EXTRA_CLASSPATH
PSEP=":"

# For Cygwin, switch paths to Windows-mixed format before running java
if $cygwin; then
# translate paths to Windows-mixed format before running java
if [ -n "$CYGPATHCMD" ]; then
[ -n "$PROG_HOME" ] &&
PROG_HOME=`cygpath -am "$PROG_HOME"`
PROG_HOME=`"$CYGPATHCMD" -am "$PROG_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath -am "$JAVA_HOME"`
JAVA_HOME=`"$CYGPATHCMD" -am "$JAVA_HOME"`
CLASSPATH_SUFFIX=";"
PSEP=";"
fi

# For Migwn, ensure paths are in UNIX format before anything is touched
if $mingw ; then
elif ($mingw || $msys); then
# For Mingw / Msys, convert paths from UNIX format before anything is touched
[ -n "$PROG_HOME" ] &&
PROG_HOME="`(cd "$PROG_HOME"; pwd -W | sed 's|/|\\\\|g')`"
[ -n "$JAVA_HOME" ] &&
Expand All @@ -95,9 +129,9 @@ fi

find_lib () {
local lib=$(find $PROG_HOME/lib/ -name "$1")
if $cygwin; then
cygpath -am $lib
elif $mingw; then
if [ -n "$CYGPATHCMD" ]; then
$CYGPATHCMD -am $lib
elif ($mingw || $msys); then
echo $lib | sed 's|/|\\\\|g'
else
echo $lib
Expand All @@ -116,7 +150,7 @@ SBT_INTF=$(find_lib "*compiler-interface*")
JLINE_READER=$(find_lib "*jline-reader-3*")
JLINE_TERMINAL=$(find_lib "*jline-terminal-3*")
JLINE_TERMINAL_JNA=$(find_lib "*jline-terminal-jna-3*")
JNA=$(find_lib "*jna-5*")
[[ ($mingw||$msys) ]] || JNA=$(find_lib "*jna-5*")

# debug
DEBUG_STR=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
26 changes: 20 additions & 6 deletions dist/bin/scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ while [[ $# -gt 0 ]]; do
DEBUG="$DEBUG_STR"
shift
;;
-version)
# defer to scalac, then exit
addScalacOptions "${1}"
shift
eval "\"$PROG_HOME/bin/scalac\" ${cp_arg-} ${java_options[@]}"
scala_exit_status=$?
onExit
;;
-J*)
addJvmOptions "${1:2}"
addScalacOptions "${1}"
Expand All @@ -115,26 +123,29 @@ while [[ $# -gt 0 ]]; do
done

if [ $execute_script == true ]; then
[ -n "$script_trace" ] && set -x
[ -n "${script_trace-}" ] && set -x
if [ "$CLASS_PATH" ]; then
cp_arg="-classpath \"$CLASS_PATH\""
fi
java_options+=(${scala_script_options})
setScriptName="-Dscript.path=$target_script"
target_jar="${target_script%.*}.jar"
if [[ $save_compiled == true && "$target_jar" -nt "$target_script" ]]; then
eval exec "\"$JAVACMD\"" $setScriptName -jar "$target_jar" "${script_args[@]}"
eval "\"$JAVACMD\"" $setScriptName -jar "$target_jar" "${script_args[@]}"
scala_exit_status=$?
else
[[ $save_compiled == true ]] && rm -f $target_jar
residual_args+=($setScriptName)
eval "\"$PROG_HOME/bin/scalac\" $cp_arg ${java_options[@]} ${residual_args[@]} -script $target_script ${script_args[@]}"
eval "\"$PROG_HOME/bin/scalac\" ${cp_arg-} ${java_options[@]} ${residual_args[@]} -script $target_script ${script_args[@]}"
scala_exit_status=$?
fi
elif [ $execute_repl == true ] || ([ $execute_run == false ] && [ $options_indicator == 0 ]); then
if [ "$CLASS_PATH" ]; then
cp_arg="-classpath \"$CLASS_PATH\""
fi
echo "Starting scala3 REPL..."
eval "\"$PROG_HOME/bin/scalac\" $cp_arg ${java_options[@]} -repl ${residual_args[@]}"
eval "\"$PROG_HOME/bin/scalac\" ${cp_arg-} ${java_options[@]} -repl ${residual_args[@]}"
scala_exit_status=$?
elif [ $execute_repl == true ] || [ ${#residual_args[@]} -ne 0 ]; then
cp_arg="$DOTTY_LIB$PSEP$SCALA_LIB"
if [ -z "$CLASS_PATH" ]; then
Expand All @@ -148,7 +159,10 @@ elif [ $execute_repl == true ] || [ ${#residual_args[@]} -ne 0 ]; then
if [ $with_compiler == true ]; then
cp_arg+="$PSEP$DOTTY_COMP$PSEP$TASTY_CORE$PSEP$DOTTY_INTF$PSEP$SCALA_ASM$PSEP$DOTTY_STAGING$PSEP$DOTTY_TASTY_INSPECTOR"
fi
eval exec "\"$JAVACMD\"" "$DEBUG" "-classpath \"$cp_arg\"" "${jvm_options[@]}" "${residual_args[@]}"
# exec here would prevent onExit from being called, leaving terminal in unusable state
eval "\"$JAVACMD\"" "$DEBUG" "-classpath \"$cp_arg\"" "${jvm_options[@]}" "${residual_args[@]}"
scala_exit_status=$?
else
echo "warning: command option is not correct."
echo "warning: command option is not correct."
fi
onExit
6 changes: 3 additions & 3 deletions dist/bin/scalac
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ classpathArgs () {
toolchain+="$JLINE_READER$PSEP"
toolchain+="$JLINE_TERMINAL$PSEP"
toolchain+="$JLINE_TERMINAL_JNA$PSEP"
toolchain+="$JNA"
toolchain+="$JNA$PSEP"

jvm_cp_args="-classpath \"$toolchain\""
}
Expand Down Expand Up @@ -123,12 +123,12 @@ fi

eval exec "\"$JAVACMD\"" \
${JAVA_OPTS:-$default_java_opts} \
"$DEBUG" \
"${DEBUG-}" \
"${java_args[@]}" \
"$jvm_cp_args" \
-Dscala.usejavacp=true \
"$PROG_NAME" \
"${scala_args[@]}" \
"${residual_args[@]}" \
"$scripting_string"
"${scripting_string-}"
exit $?