From 73bb88da4ae92ebc41b8a6079291b55bd2836a23 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 19 Sep 2021 11:04:27 -0600 Subject: [PATCH 1/9] insert compiler libraries head of user-specified classpath --- .../src/dotty/tools/MainGenericRunner.scala | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index af23cf08728d..2a15ed41c31c 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -16,6 +16,9 @@ import java.util.jar._ import java.util.jar.Attributes.Name import dotty.tools.io.Jar import dotty.tools.runner.ScalaClassLoader +import java.nio.file.{Files, Paths, Path} +import scala.collection.JavaConverters._ +import dotty.tools.dotc.config.CommandLineParser enum ExecuteMode: case Guess @@ -123,7 +126,8 @@ object MainGenericRunner { case (o @ javaOption(striped)) :: tail => process(tail, settings.withJavaArgs(striped).withScalaArgs(o)) case (o @ scalaOption(_*)) :: tail => - process(tail, settings.withScalaArgs(o)) + val remainingArgs = (expandArg(o) ++ tail).toList + process(remainingArgs, settings) case (o @ colorOption(_*)) :: tail => process(tail, settings.withScalaArgs(o)) case arg :: tail => @@ -137,6 +141,19 @@ object MainGenericRunner { val newSettings = if arg.startsWith("-") then settings else settings.withPossibleEntryPaths(arg).withModeShouldBePossibleRun process(tail, newSettings.withResidualArgs(arg)) + // copy of method private to dotty.tools.dotc.config.CliCommand.distill() + // TODO: make it available as a public method and remove this copy? + def expandArg(arg: String): List[String] = + def stripComment(s: String) = s takeWhile (_ != '#') + val path = Paths.get(arg stripPrefix "@") + if (!Files.exists(path)) + System.err.println(s"Argument file ${path.getFileName} could not be found") + Nil + else + val lines = Files.readAllLines(path) // default to UTF-8 encoding + val params = lines.asScala map stripComment mkString " " + CommandLineParser.tokenize(params) + def main(args: Array[String]): Unit = val scalaOpts = envOrNone("SCALA_OPTS").toArray.flatMap(_.split(" ")) val allArgs = scalaOpts ++ args From 29c20d008bfb3764ef4d90e8b36ac366d77e20d8 Mon Sep 17 00:00:00 2001 From: Phil Date: Sun, 19 Sep 2021 11:13:40 -0600 Subject: [PATCH 2/9] reorder scalaArgs ahead of -script arg --- compiler/src/dotty/tools/MainGenericRunner.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index 2a15ed41c31c..59e63894397e 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -208,8 +208,8 @@ object MainGenericRunner { List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) ++ settings.residualArgs ++ (if settings.save then List("-save") else Nil) - ++ List("-script", settings.targetScript) ++ settings.scalaArgs + ++ List("-script", settings.targetScript) ++ settings.scriptArgs scripting.Main.main(properArgs.toArray) case ExecuteMode.Guess => From f1f8b7b3eea47c4923e95061eea5e0fb546da601 Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 20 Sep 2021 16:35:40 -0600 Subject: [PATCH 3/9] refactor CliCommand.expandArg method; fix script.path regression, Windows classpath regression --- .../src/dotty/tools/MainGenericRunner.scala | 17 +--- .../dotty/tools/dotc/config/CliCommand.scala | 19 +--- .../tools/dotc/config/CommandLineParser.scala | 17 ++++ .../tools/coursier/CoursierScalaTests.scala | 9 ++ compiler/test-coursier/run/myargs.txt | 1 + .../scripting/argfileClasspath.sc | 9 ++ .../scripting/classpathReport.sc | 9 +- .../scripting/cpArgumentsFile.txt | 1 + .../test-resources/scripting/scriptPath.sc | 7 +- .../tools/scripting/BashScriptsTests.scala | 28 +++--- .../tools/scripting/ClasspathTests.scala | 88 ++----------------- dist/bin/scala | 31 ++++++- 12 files changed, 106 insertions(+), 130 deletions(-) create mode 100755 compiler/test-coursier/run/myargs.txt create mode 100755 compiler/test-resources/scripting/argfileClasspath.sc create mode 100755 compiler/test-resources/scripting/cpArgumentsFile.txt diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index 59e63894397e..b78c4c1da631 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -126,7 +126,7 @@ object MainGenericRunner { case (o @ javaOption(striped)) :: tail => process(tail, settings.withJavaArgs(striped).withScalaArgs(o)) case (o @ scalaOption(_*)) :: tail => - val remainingArgs = (expandArg(o) ++ tail).toList + val remainingArgs = (CommandLineParser.expandArg(o) ++ tail).toList process(remainingArgs, settings) case (o @ colorOption(_*)) :: tail => process(tail, settings.withScalaArgs(o)) @@ -141,19 +141,6 @@ object MainGenericRunner { val newSettings = if arg.startsWith("-") then settings else settings.withPossibleEntryPaths(arg).withModeShouldBePossibleRun process(tail, newSettings.withResidualArgs(arg)) - // copy of method private to dotty.tools.dotc.config.CliCommand.distill() - // TODO: make it available as a public method and remove this copy? - def expandArg(arg: String): List[String] = - def stripComment(s: String) = s takeWhile (_ != '#') - val path = Paths.get(arg stripPrefix "@") - if (!Files.exists(path)) - System.err.println(s"Argument file ${path.getFileName} could not be found") - Nil - else - val lines = Files.readAllLines(path) // default to UTF-8 encoding - val params = lines.asScala map stripComment mkString " " - CommandLineParser.tokenize(params) - def main(args: Array[String]): Unit = val scalaOpts = envOrNone("SCALA_OPTS").toArray.flatMap(_.split(" ")) val allArgs = scalaOpts ++ args @@ -204,6 +191,8 @@ object MainGenericRunner { } errorFn("", res) case ExecuteMode.Script => + val targetScriptPath: String = settings.targetScript.toString.replace('\\', '/') + System.setProperty("script.path", targetScriptPath) val properArgs = List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) ++ settings.residualArgs diff --git a/compiler/src/dotty/tools/dotc/config/CliCommand.scala b/compiler/src/dotty/tools/dotc/config/CliCommand.scala index 01ec346000c1..1e61914a89ca 100644 --- a/compiler/src/dotty/tools/dotc/config/CliCommand.scala +++ b/compiler/src/dotty/tools/dotc/config/CliCommand.scala @@ -7,8 +7,7 @@ import Settings._ import core.Contexts._ import Properties._ - import scala.PartialFunction.cond - import scala.collection.JavaConverters._ +import scala.PartialFunction.cond trait CliCommand: @@ -42,24 +41,10 @@ trait CliCommand: /** Distill arguments into summary detailing settings, errors and files to main */ def distill(args: Array[String], sg: Settings.SettingGroup)(ss: SettingsState = sg.defaultState)(using Context): ArgsSummary = - /** - * Expands all arguments starting with @ to the contents of the - * file named like each argument. - */ - def expandArg(arg: String): List[String] = - def stripComment(s: String) = s takeWhile (_ != '#') - val path = Paths.get(arg stripPrefix "@") - if (!Files.exists(path)) - report.error(s"Argument file ${path.getFileName} could not be found") - Nil - else - val lines = Files.readAllLines(path) // default to UTF-8 encoding - val params = lines.asScala map stripComment mkString " " - CommandLineParser.tokenize(params) // expand out @filename to the contents of that filename def expandedArguments = args.toList flatMap { - case x if x startsWith "@" => expandArg(x) + case x if x startsWith "@" => CommandLineParser.expandArg(x) case x => List(x) } diff --git a/compiler/src/dotty/tools/dotc/config/CommandLineParser.scala b/compiler/src/dotty/tools/dotc/config/CommandLineParser.scala index e3ca896d18d2..91017f7fc0c0 100644 --- a/compiler/src/dotty/tools/dotc/config/CommandLineParser.scala +++ b/compiler/src/dotty/tools/dotc/config/CommandLineParser.scala @@ -3,6 +3,8 @@ package dotty.tools.dotc.config import scala.annotation.tailrec import scala.collection.mutable.ArrayBuffer import java.lang.Character.isWhitespace +import java.nio.file.{Files, Paths} +import scala.collection.JavaConverters._ /** A simple enough command line parser. */ @@ -93,4 +95,19 @@ object CommandLineParser: def tokenize(line: String): List[String] = tokenize(line, x => throw new ParseException(x)) + /** + * Expands all arguments starting with @ to the contents of the + * file named like each argument. + */ + def expandArg(arg: String): List[String] = + def stripComment(s: String) = s takeWhile (_ != '#') + val path = Paths.get(arg stripPrefix "@") + if (!Files.exists(path)) + System.err.println(s"Argument file ${path.getFileName} could not be found") + Nil + else + val lines = Files.readAllLines(path) // default to UTF-8 encoding + val params = lines.asScala map stripComment mkString " " + tokenize(params) + class ParseException(msg: String) extends RuntimeException(msg) diff --git a/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala b/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala index e932ac54089a..db033d5afd36 100644 --- a/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala +++ b/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala @@ -122,6 +122,15 @@ class CoursierScalaTests: assertTrue(output.mkString("\n").contains("Unable to create a system terminal")) // Scala attempted to create REPL so we can assume it is working replWithArgs() + def argumentFile() = + // verify that an arguments file is accepted + // verify that setting a user classpath does not remove compiler libraries from the classpath. + // arguments file contains "-classpath .", adding current directory to classpath. + val source = new File(getClass.getResource("/run/myfile.scala").getPath) + val argsFile = new File(getClass.getResource("/run/myargs.txt").getPath) + val output = CoursierScalaTests.csScalaCmd(s"@$argsFile", source.absPath) + assertEquals(output.mkString("\n"), "Hello") + object CoursierScalaTests: def execCmd(command: String, options: String*): List[String] = diff --git a/compiler/test-coursier/run/myargs.txt b/compiler/test-coursier/run/myargs.txt new file mode 100755 index 000000000000..a0d2d24986de --- /dev/null +++ b/compiler/test-coursier/run/myargs.txt @@ -0,0 +1 @@ +-classpath . diff --git a/compiler/test-resources/scripting/argfileClasspath.sc b/compiler/test-resources/scripting/argfileClasspath.sc new file mode 100755 index 000000000000..c31371ba8934 --- /dev/null +++ b/compiler/test-resources/scripting/argfileClasspath.sc @@ -0,0 +1,9 @@ +#!dist/target/pack/bin/scala @compiler/test-resources/scripting/cpArgumentsFile.txt + +import java.nio.file.Paths + +def main(args: Array[String]): Unit = + val cwd = Paths.get(".").toAbsolutePath.toString.replace('\\', '/').replaceAll("/$", "") + printf("cwd: %s\n", cwd) + printf("classpath: %s\n", sys.props("java.class.path")) + diff --git a/compiler/test-resources/scripting/classpathReport.sc b/compiler/test-resources/scripting/classpathReport.sc index 5ccfd6faca76..e7b2f7067a1f 100755 --- a/compiler/test-resources/scripting/classpathReport.sc +++ b/compiler/test-resources/scripting/classpathReport.sc @@ -1,9 +1,12 @@ -#!dist/target/pack/bin/scala -classpath 'dist/target/pack/lib/*' +#!dist/target/pack/bin/scala -classpath dist/target/pack/lib/* import java.nio.file.Paths def main(args: Array[String]): Unit = - val cwd = Paths.get(".").toAbsolutePath.toString.replace('\\', '/').replaceAll("/$", "") + val cwd = Paths.get(".").toAbsolutePath.normalize.toString.norm printf("cwd: %s\n", cwd) - printf("classpath: %s\n", sys.props("java.class.path")) + printf("classpath: %s\n", sys.props("java.class.path").norm) + +extension(s: String) + def norm: String = s.replace('\\', '/') diff --git a/compiler/test-resources/scripting/cpArgumentsFile.txt b/compiler/test-resources/scripting/cpArgumentsFile.txt new file mode 100755 index 000000000000..73037eb7d9bc --- /dev/null +++ b/compiler/test-resources/scripting/cpArgumentsFile.txt @@ -0,0 +1 @@ +-classpath dist/target/pack/lib/* diff --git a/compiler/test-resources/scripting/scriptPath.sc b/compiler/test-resources/scripting/scriptPath.sc index 49ed65a76515..3ce97ac44508 100755 --- a/compiler/test-resources/scripting/scriptPath.sc +++ b/compiler/test-resources/scripting/scriptPath.sc @@ -1,10 +1,13 @@ -#!/usr/bin/env scala +#!dist/target/pack/bin/scala def main(args: Array[String]): Unit = args.zipWithIndex.foreach { case (arg,i) => printf("arg %d: [%s]\n",i,arg) } val path = Option(sys.props("script.path")) match { case None => printf("no script.path property is defined\n") case Some(path) => - printf("script.path: %s\n",path) + printf("script.path: %s\n",path.norm) assert(path.endsWith("scriptPath.sc"),s"actual path [$path]") } + + extension(s: String) + def norm: String = s.replace('\\', '/') diff --git a/compiler/test/dotty/tools/scripting/BashScriptsTests.scala b/compiler/test/dotty/tools/scripting/BashScriptsTests.scala index 4c0c17ec6cd1..a652ba8a5a43 100644 --- a/compiler/test/dotty/tools/scripting/BashScriptsTests.scala +++ b/compiler/test/dotty/tools/scripting/BashScriptsTests.scala @@ -84,12 +84,12 @@ class BashScriptsTests: @Test def verifyScriptPathProperty = val scriptFile = testFiles.find(_.getName == "scriptPath.sc").get val expected = s"/${scriptFile.getName}" - printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName) + System.err.printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName) val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath) if exitCode == 0 && ! stderr.exists(_.contains("Permission denied")) then // var cmd = Array(bashExe, "-c", scriptFile.absPath) // val stdout = Process(cmd).lazyLines_! - stdout.foreach { printf("######### [%s]\n", _) } + stdout.foreach { System.err.printf("######### [%s]\n", _) } val valid = stdout.exists { _.endsWith(expected) } if valid then printf("# valid script.path reported by [%s]\n", scriptFile.getName) assert(valid, s"script ${scriptFile.absPath} did not report valid script.path value") @@ -99,35 +99,39 @@ class BashScriptsTests: */ @Test def verifyScalaOpts = val scriptFile = testFiles.find(_.getName == "classpathReport.sc").get - printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName) + printf("===> verify SCALA_OPTS -classpath setting in argument file seen by script [%s]\n", scriptFile.getName) val argsfile = createArgsFile() // avoid problems caused by drive letter val envPairs = List(("SCALA_OPTS", s"@$argsfile")) val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath, envPairs:_*) + printf("\n") if exitCode != 0 || stderr.exists(_.contains("Permission denied")) then stderr.foreach { System.err.printf("stderr [%s]\n", _) } printf("unable to execute script, return value is %d\n", exitCode) else - // val stdout: Seq[String] = Process(cmd, cwd, envPairs:_*).lazyLines_!.toList - val expected = s"${cwd.toString}" + val expected = cwd val List(line1: String, line2: String) = stdout.take(2) + printf("line1 [%s]\n", line1) val valid = line2.dropWhile( _ != ' ').trim.startsWith(expected) + val psep = if osname.startsWith("Windows") then ';' else ':' + printf("line2 start [%s]\n", line2.take(100)) if valid then printf(s"\n===> success: classpath begins with %s, as reported by [%s]\n", cwd, scriptFile.getName) - assert(valid, s"script ${scriptFile.absPath} did not report valid java.class.path first entry") + assert(valid, s"script ${scriptFile.getName} did not report valid java.class.path first entry") - lazy val cwd = Paths.get(dotty.tools.dotc.config.Properties.userDir).toFile + lazy val cwd: String = Paths.get(".").toAbsolutePath.normalize.toString.norm def createArgsFile(): String = val utfCharset = java.nio.charset.StandardCharsets.UTF_8.name - val text = s"-classpath ${cwd.absPath}" + val text = s"-classpath $cwd" val path = Files.createTempFile("scriptingTest", ".args") Files.write(path, text.getBytes(utfCharset)) - path.toFile.getAbsolutePath.replace('\\', '/') + path.toFile.getAbsolutePath.norm - extension (str: String) def dropExtension: String = - str.reverse.dropWhile(_ != '.').drop(1).reverse + extension(str: String) + def norm: String = str.replace('\\', '/') + def dropExtension: String = str.reverse.dropWhile(_ != '.').drop(1).reverse extension(f: File) def absPath: String = - f.getAbsolutePath.replace('\\', '/') + f.getAbsolutePath.norm lazy val osname = Option(sys.props("os.name")).getOrElse("").toLowerCase diff --git a/compiler/test/dotty/tools/scripting/ClasspathTests.scala b/compiler/test/dotty/tools/scripting/ClasspathTests.scala index 7ef0f9ee3fb3..21a9ce10d387 100755 --- a/compiler/test/dotty/tools/scripting/ClasspathTests.scala +++ b/compiler/test/dotty/tools/scripting/ClasspathTests.scala @@ -13,104 +13,29 @@ import scala.sys.process._ import scala.jdk.CollectionConverters._ import dotty.tools.dotc.config.Properties._ -/** Runs all tests contained in `compiler/test-resources/scripting/` */ +/** Test java command line generated by bin/scala and bin/scalac */ class ClasspathTests: val packBinDir = "dist/target/pack/bin" - val scalaCopy = makeTestableScriptCopy("scala") - val scalacCopy = makeTestableScriptCopy("scalac") - val commonCopy = makeTestableScriptCopy("common") + val packLibDir = "dist/target/pack/lib" // only interested in classpath test scripts - def testFiles = scripts("/scripting").filter { _.getName.matches("classpath.*[.]sc") } val testScriptName = "classpathReport.sc" - def testScript = testFiles.find { _.getName == testScriptName } match + val testScript = scripts("/scripting").find { _.getName.matches(testScriptName) } match case None => sys.error(s"test script not found: ${testScriptName}") case Some(file) => file - def getScriptPath(scriptName: String): Path = Paths.get(s"$packBinDir/$scriptName") - def exists(scriptPath: Path): Boolean = Files.exists(scriptPath) def packBinScalaExists:Boolean = exists(Paths.get(s"$packBinDir/scala")) - // create edited copy of [dist/bin/scala] and [dist/bin/scalac] for scalacEchoTest - def makeTestableScriptCopy(scriptName: String): Path = - val scriptPath: Path = getScriptPath(scriptName) - val scriptCopy: Path = getScriptPath(s"$scriptName-copy") - if Files.exists(scriptPath) then - val lines = Files.readAllLines(scriptPath).asScala.map { - _.replaceAll("/scalac", "/scalac-copy"). - replaceAll("/common", "/common-copy"). - replaceFirst("^ *eval(.*JAVACMD.*)", "echo $1") - } - val bytes = (lines.mkString("\n")+"\n").getBytes - Files.write(scriptCopy, bytes) - - scriptCopy - - /* - * verify java command line generated by scalac. - */ - @Test def scalacEchoTest = - val relpath = testScript.toPath.relpath.norm - printf("===> scalacEchoTest for script [%s]\n", relpath) - printf("bash is [%s]\n", bashExe) - - if packBinScalaExists then - val bashCmdline = s"SCALA_OPTS= ${scalaCopy.norm} -classpath '$wildcardEntry' $relpath" - - // ask [dist/bin/scalac] to echo generated command line so we can verify some things - val cmd = Array(bashExe, "-c", bashCmdline) - - //cmd.foreach { printf("[%s]\n", _) } - - val javaCommandLine = exec(cmd:_*).mkString(" ").split(" ").filter { _.trim.nonEmpty } - printf("\n==================== isWin[%s], cygwin[%s], mingw[%s], msys[%s]\n", isWin, cygwin, mingw, msys) - javaCommandLine.foreach { printf("java-command[%s]\n", _) } - - val output = scala.collection.mutable.Queue(javaCommandLine:_*) - output.dequeueWhile( _ != "dotty.tools.scripting.Main") - - def consumeNext = if output.isEmpty then "" else output.dequeue() - - // assert that we found "dotty.tools.scripting.Main" - val str = consumeNext - if str != "dotty.tools.scripting.Main" then - - assert(str == "dotty.tools.scripting.Main", s"found [$str]") - val mainArgs = output.copyToArray(Array.ofDim[String](output.length)) - - // display command line starting with "dotty.tools.scripting.Main" - output.foreach { line => - printf("%s\n", line) - } - - // expecting -classpath next - assert(consumeNext.replaceAll("'", "") == "-classpath") - - // 2nd arg to scripting.Main is 'lib/*', with semicolon added if Windows jdk - - // PR #10761: verify that [dist/bin/scala] -classpath processing adds $psep to wildcard if Windows - val classpathValue = consumeNext - printf("classpath value [%s]\n", classpathValue) - assert( !winshell || classpathValue.contains(psep) ) - - // expecting -script next - assert(consumeNext.replaceAll("'", "") == "-script") - - // PR #10761: verify that Windows jdk did not expand single wildcard classpath to multiple file paths - if javaCommandLine.last != relpath then - printf("last: %s\nrelp: %s\n", javaCommandLine.last, relpath) - assert(javaCommandLine.last == relpath, s"unexpected output passed to scripting.Main") - /* * verify classpath reported by called script. */ - @Test def hashbangClasspathVerifyTest = + @Test def hashbangClasspathVerifyTest = { val relpath = testScript.toPath.relpath.norm printf("===> hashbangClasspathVerifyTest for script [%s]\n", relpath) printf("bash is [%s]\n", bashExe) - if false && packBinScalaExists then + if packBinScalaExists then val bashCmdline = s"SCALA_OPTS= $relpath" val cmd = Array(bashExe, "-c", bashCmdline) @@ -123,7 +48,7 @@ class ClasspathTests: val scriptCp = findTaggedLine("classpath", scriptOutput) val hashbangClasspathJars = scriptCp.split(psep).map { _.getName }.sorted.distinct - val packlibJars = listJars(s"$scriptCwd/dist/target/pack/lib").sorted.distinct + val packlibJars = listJars(s"$scriptCwd/$packLibDir").sorted.distinct // verify that the classpath set in the hashbang line is effective if hashbangClasspathJars.size != packlibJars.size then @@ -131,6 +56,7 @@ class ClasspathTests: printf("%d jar files in dist/target/pack/lib\n", packlibJars.size) assert(hashbangClasspathJars.size == packlibJars.size) + } //////////////// end of tests //////////////// diff --git a/dist/bin/scala b/dist/bin/scala index b1e3d4e66e3e..7138b9a69ec0 100755 --- a/dist/bin/scala +++ b/dist/bin/scala @@ -28,10 +28,39 @@ fi source "$PROG_HOME/bin/common" +case `uname` in +CYG*|MINGW*|MSYS*) PSEP=';' ;; +*) PSEP=':' ;; +esac + +ARGS=() +while [ $# -gt 0 ]; do + case "$1" in + -cp | -classpath) # partial fix for #10761 + # passed as two arguments, e.g. '-classpath' 'lib/*' + ARGS+=($1) + ARGS+=("$2${PSEP}") + shift + shift + ;; + -cp*|-classpath*) # partial fix for #10761 + # passed as a single argument, e.g. '-classpath lib/*' + # (hashbang line can glom args together) + ARGS+=('-classpath') + ARGS+=("\"${1#* *}${PSEP}\"") + shift + ;; + *) + ARGS+=($1) + shift + ;; + esac +done + # exec here would prevent onExit from being called, leaving terminal in unusable state compilerJavaClasspathArgs [ -z "${ConEmuPID-}" -o -n "${cygwin-}" ] && export MSYSTEM= PWD= # workaround for #12405 -eval "\"$JAVACMD\"" "-classpath \"$jvm_cp_args\"" "dotty.tools.MainGenericRunner" "-classpath \"$jvm_cp_args\"" "$@" +eval "\"$JAVACMD\"" "-classpath \"$jvm_cp_args\"" "dotty.tools.MainGenericRunner" "-classpath \"$jvm_cp_args\"" "${ARGS[@]}" scala_exit_status=$? From 8104575c1fce0c5e76a6b134318dc84e2777ce81 Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 21 Sep 2021 15:44:29 -0600 Subject: [PATCH 4/9] resolve Windows classpath regression in MainGenericRunner rather than dist/bin/scala --- .../src/dotty/tools/MainGenericRunner.scala | 25 ++++++++++++--- .../tools/coursier/CoursierScalaTests.scala | 1 + .../tools/scripting/ClasspathTests.scala | 4 ++- dist/bin/scala | 31 +------------------ 4 files changed, 25 insertions(+), 36 deletions(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index b78c4c1da631..c6a6521ecc86 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -105,7 +105,17 @@ object MainGenericRunner { case "-run" :: fqName :: tail => process(tail, settings.withExecuteMode(ExecuteMode.Run).withTargetToRun(fqName)) case ("-cp" | "-classpath" | "--class-path") :: cp :: tail => - process(tail, settings.copy(classPath = settings.classPath.appended(cp))) + val (tailargs, cpstr) = if classpathSeparator != ';' || cp.contains(classpathSeparator) then + (tail, cp) + else + val globdir = cp.replace('\\', '/').replaceAll("/[^/]*$","") + val jarfiles = cp :: tail + val cpfiles = jarfiles.takeWhile( f => f.startsWith(globdir) && ((f.toLowerCase.endsWith(".jar") || f.endsWith(".zip"))) ) + val tailargs = jarfiles.drop(cpfiles.size) + (tailargs, cpfiles.mkString(classpathSeparator)) + + process(tailargs, settings.copy(classPath = settings.classPath.appended(cpstr))) + case ("-version" | "--version") :: _ => settings.copy( executeMode = ExecuteMode.Repl, @@ -141,6 +151,13 @@ object MainGenericRunner { val newSettings = if arg.startsWith("-") then settings else settings.withPossibleEntryPaths(arg).withModeShouldBePossibleRun process(tail, newSettings.withResidualArgs(arg)) + // collect globbed classpath entries + def collectGlobbedEntries(entries: List[String]): (List[String], List[String]) = { + val cpfiles = entries.takeWhile( f => (f.toLowerCase.endsWith(".jar") || f.endsWith(".zip")) ) + val remainder = entries.drop(cpfiles.size) + (cpfiles, remainder) + } + def main(args: Array[String]): Unit = val scalaOpts = envOrNone("SCALA_OPTS").toArray.flatMap(_.split(" ")) val allArgs = scalaOpts ++ args @@ -155,7 +172,7 @@ object MainGenericRunner { repl.Main.main(properArgs.toArray) case ExecuteMode.PossibleRun => - val newClasspath = (settings.classPath :+ ".").map(File(_).toURI.toURL) + val newClasspath = (settings.classPath :+ ".").flatMap(_.split(classpathSeparator).filter(_.nonEmpty)).map(File(_).toURI.toURL) import dotty.tools.runner.RichClassLoader._ val newClassLoader = ScalaClassLoader.fromURLsParallelCapable(newClasspath) val targetToRun = settings.possibleEntryPaths.to(LazyList).find { entryPath => @@ -177,8 +194,7 @@ object MainGenericRunner { cp.filterNot(c => compilerLibs.exists(c.contains)) else cp - val newClasspath = (settings.classPath ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) - + val newClasspath = (settings.classPath.flatMap(_.split(classpathSeparator).filter(_.nonEmpty)) ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) val res = ObjectRunner.runAndCatch(newClasspath, settings.targetToRun, settings.residualArgs).flatMap { case ex: ClassNotFoundException if ex.getMessage == settings.targetToRun => val file = settings.targetToRun @@ -192,7 +208,6 @@ object MainGenericRunner { errorFn("", res) case ExecuteMode.Script => val targetScriptPath: String = settings.targetScript.toString.replace('\\', '/') - System.setProperty("script.path", targetScriptPath) val properArgs = List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) ++ settings.residualArgs diff --git a/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala b/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala index db033d5afd36..2e616eeea631 100644 --- a/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala +++ b/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala @@ -130,6 +130,7 @@ class CoursierScalaTests: val argsFile = new File(getClass.getResource("/run/myargs.txt").getPath) val output = CoursierScalaTests.csScalaCmd(s"@$argsFile", source.absPath) assertEquals(output.mkString("\n"), "Hello") + argumentFile() object CoursierScalaTests: diff --git a/compiler/test/dotty/tools/scripting/ClasspathTests.scala b/compiler/test/dotty/tools/scripting/ClasspathTests.scala index 21a9ce10d387..159605cd967c 100755 --- a/compiler/test/dotty/tools/scripting/ClasspathTests.scala +++ b/compiler/test/dotty/tools/scripting/ClasspathTests.scala @@ -76,7 +76,9 @@ lazy val env:Map[String, String] = System.getenv.asScala.toMap // script output expected as ": " def findTaggedLine(tag: String, lines: Seq[String]): String = lines.find { _.startsWith(tag) } match - case None => sys.error(s"no $tag: found in script output") + case None => + lines.foreach { System.err.printf("line[%s]\n", _) } + sys.error(s"no $tag: found in script output") case Some(cwd) => cwd.dropWhile( _ != ' ').trim // discard tag def exec(cmd: String *): Seq[String] = Process(cmd).lazyLines_!.toList diff --git a/dist/bin/scala b/dist/bin/scala index 7138b9a69ec0..b1e3d4e66e3e 100755 --- a/dist/bin/scala +++ b/dist/bin/scala @@ -28,39 +28,10 @@ fi source "$PROG_HOME/bin/common" -case `uname` in -CYG*|MINGW*|MSYS*) PSEP=';' ;; -*) PSEP=':' ;; -esac - -ARGS=() -while [ $# -gt 0 ]; do - case "$1" in - -cp | -classpath) # partial fix for #10761 - # passed as two arguments, e.g. '-classpath' 'lib/*' - ARGS+=($1) - ARGS+=("$2${PSEP}") - shift - shift - ;; - -cp*|-classpath*) # partial fix for #10761 - # passed as a single argument, e.g. '-classpath lib/*' - # (hashbang line can glom args together) - ARGS+=('-classpath') - ARGS+=("\"${1#* *}${PSEP}\"") - shift - ;; - *) - ARGS+=($1) - shift - ;; - esac -done - # exec here would prevent onExit from being called, leaving terminal in unusable state compilerJavaClasspathArgs [ -z "${ConEmuPID-}" -o -n "${cygwin-}" ] && export MSYSTEM= PWD= # workaround for #12405 -eval "\"$JAVACMD\"" "-classpath \"$jvm_cp_args\"" "dotty.tools.MainGenericRunner" "-classpath \"$jvm_cp_args\"" "${ARGS[@]}" +eval "\"$JAVACMD\"" "-classpath \"$jvm_cp_args\"" "dotty.tools.MainGenericRunner" "-classpath \"$jvm_cp_args\"" "$@" scala_exit_status=$? From 87461becddcbd4b35415a44005f6ea62a09f3234 Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 21 Sep 2021 15:53:49 -0600 Subject: [PATCH 5/9] moved Windows classpath fix from dist/bin/scala to MainGenericRunner --- compiler/src/dotty/tools/MainGenericRunner.scala | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index c6a6521ecc86..d05c4a5d3542 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -105,9 +105,10 @@ object MainGenericRunner { case "-run" :: fqName :: tail => process(tail, settings.withExecuteMode(ExecuteMode.Run).withTargetToRun(fqName)) case ("-cp" | "-classpath" | "--class-path") :: cp :: tail => - val (tailargs, cpstr) = if classpathSeparator != ';' || cp.contains(classpathSeparator) then + val (tailargs, cpstr) = if classpathSeparator != ";" || cp.contains(classpathSeparator) then (tail, cp) else + // combine globbed classpath entries into a classpath val globdir = cp.replace('\\', '/').replaceAll("/[^/]*$","") val jarfiles = cp :: tail val cpfiles = jarfiles.takeWhile( f => f.startsWith(globdir) && ((f.toLowerCase.endsWith(".jar") || f.endsWith(".zip"))) ) @@ -151,13 +152,6 @@ object MainGenericRunner { val newSettings = if arg.startsWith("-") then settings else settings.withPossibleEntryPaths(arg).withModeShouldBePossibleRun process(tail, newSettings.withResidualArgs(arg)) - // collect globbed classpath entries - def collectGlobbedEntries(entries: List[String]): (List[String], List[String]) = { - val cpfiles = entries.takeWhile( f => (f.toLowerCase.endsWith(".jar") || f.endsWith(".zip")) ) - val remainder = entries.drop(cpfiles.size) - (cpfiles, remainder) - } - def main(args: Array[String]): Unit = val scalaOpts = envOrNone("SCALA_OPTS").toArray.flatMap(_.split(" ")) val allArgs = scalaOpts ++ args From a56c284124977ab2110d963c010677a393eaa4ac Mon Sep 17 00:00:00 2001 From: Phil Date: Tue, 21 Sep 2021 17:10:36 -0600 Subject: [PATCH 6/9] use slash-agnostic globdir test to recombine globbed classpath --- compiler/src/dotty/tools/MainGenericRunner.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index d05c4a5d3542..34e75beb410f 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -109,7 +109,7 @@ object MainGenericRunner { (tail, cp) else // combine globbed classpath entries into a classpath - val globdir = cp.replace('\\', '/').replaceAll("/[^/]*$","") + val globdir = cp.replaceAll("[\\/][^\\/]*$","") // must be forward-backward-slash-agnostic val jarfiles = cp :: tail val cpfiles = jarfiles.takeWhile( f => f.startsWith(globdir) && ((f.toLowerCase.endsWith(".jar") || f.endsWith(".zip"))) ) val tailargs = jarfiles.drop(cpfiles.size) From b9557b01e8513412ee0e5bee70c468a7e0c73b71 Mon Sep 17 00:00:00 2001 From: Phil Date: Wed, 22 Sep 2021 07:07:13 -0600 Subject: [PATCH 7/9] remove unused code; reduce scope of when Windows classpath unglobbing occurs --- compiler/src/dotty/tools/MainGenericRunner.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index 34e75beb410f..6cb805ba2d25 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -105,17 +105,17 @@ object MainGenericRunner { case "-run" :: fqName :: tail => process(tail, settings.withExecuteMode(ExecuteMode.Run).withTargetToRun(fqName)) case ("-cp" | "-classpath" | "--class-path") :: cp :: tail => - val (tailargs, cpstr) = if classpathSeparator != ";" || cp.contains(classpathSeparator) then + val globdir = cp.replaceAll("[\\/][^\\/]*$","") // slash/backslash agnostic + val (tailargs, cpstr) = if globdir.nonEmpty && classpathSeparator != ";" || cp.contains(classpathSeparator) then (tail, cp) else // combine globbed classpath entries into a classpath - val globdir = cp.replaceAll("[\\/][^\\/]*$","") // must be forward-backward-slash-agnostic val jarfiles = cp :: tail val cpfiles = jarfiles.takeWhile( f => f.startsWith(globdir) && ((f.toLowerCase.endsWith(".jar") || f.endsWith(".zip"))) ) val tailargs = jarfiles.drop(cpfiles.size) (tailargs, cpfiles.mkString(classpathSeparator)) - process(tailargs, settings.copy(classPath = settings.classPath.appended(cpstr))) + process(tailargs, settings.copy(classPath = settings.classPath ++ cpstr.split(classpathSeparator).filter(_.nonEmpty))) case ("-version" | "--version") :: _ => settings.copy( @@ -201,7 +201,6 @@ object MainGenericRunner { } errorFn("", res) case ExecuteMode.Script => - val targetScriptPath: String = settings.targetScript.toString.replace('\\', '/') val properArgs = List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) ++ settings.residualArgs From b0b5392b3240a7af94f8e54810b6253d63cc65a8 Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 24 Sep 2021 12:14:25 -0600 Subject: [PATCH 8/9] run precompiled jar, if present and newer than script source file --- .../src/dotty/tools/MainGenericRunner.scala | 49 +++++++++++++------ .../tools/scripting/BashScriptsTests.scala | 2 +- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index 6cb805ba2d25..c0831cfc2010 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -158,6 +158,13 @@ object MainGenericRunner { val settings = process(allArgs.toList, Settings()) if settings.exitCode != 0 then System.exit(settings.exitCode) + def removeCompiler(cp: Array[String]) = + if (!settings.compiler) then // Let's remove compiler from the classpath + val compilerLibs = Seq("scala3-compiler", "scala3-interfaces", "tasty-core", "scala-asm", "scala3-staging", "scala3-tasty-inspector") + cp.filterNot(c => compilerLibs.exists(c.contains)) + else + cp + def run(settings: Settings): Unit = settings.executeMode match case ExecuteMode.Repl => val properArgs = @@ -181,13 +188,6 @@ object MainGenericRunner { run(settings.withExecuteMode(ExecuteMode.Repl)) case ExecuteMode.Run => val scalaClasspath = ClasspathFromClassloader(Thread.currentThread().getContextClassLoader).split(classpathSeparator) - - def removeCompiler(cp: Array[String]) = - if (!settings.compiler) then // Let's remove compiler from the classpath - val compilerLibs = Seq("scala3-compiler", "scala3-interfaces", "tasty-core", "scala-asm", "scala3-staging", "scala3-tasty-inspector") - cp.filterNot(c => compilerLibs.exists(c.contains)) - else - cp val newClasspath = (settings.classPath.flatMap(_.split(classpathSeparator).filter(_.nonEmpty)) ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) val res = ObjectRunner.runAndCatch(newClasspath, settings.targetToRun, settings.residualArgs).flatMap { case ex: ClassNotFoundException if ex.getMessage == settings.targetToRun => @@ -201,14 +201,33 @@ object MainGenericRunner { } errorFn("", res) case ExecuteMode.Script => - val properArgs = - List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) - ++ settings.residualArgs - ++ (if settings.save then List("-save") else Nil) - ++ settings.scalaArgs - ++ List("-script", settings.targetScript) - ++ settings.scriptArgs - scripting.Main.main(properArgs.toArray) + val targetScript = Paths.get(settings.targetScript) + val targetJar = settings.targetScript.replaceAll("[.][^\\/]*$","")+".jar" + val precompiledJar = Paths.get(targetJar) + def mainClass = Jar(targetJar).mainClass match + case Some(mc) => + mc + case None => + "" + if precompiledJar.toFile.isFile && mainClass.nonEmpty && precompiledJar.toFile.lastModified >= targetScript.toFile.lastModified then + // precompiledJar is newer than targetScript + sys.props("script.path") = targetScript.toAbsolutePath.normalize.toString + val scalaClasspath = ClasspathFromClassloader(Thread.currentThread().getContextClassLoader).split(classpathSeparator) + val newClasspath = (settings.classPath.flatMap(_.split(classpathSeparator).filter(_.nonEmpty)) ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) + Jar(targetJar).mainClass match + case Some(mc) => + ObjectRunner.runAndCatch(newClasspath :+ File(targetJar).toURI.toURL, mc, settings.residualArgs) + case None => + Some(IllegalArgumentException(s"No main class defined in manifest in jar: $precompiledJar")) + else + val properArgs = + List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) + ++ settings.residualArgs + ++ (if settings.save then List("-save") else Nil) + ++ settings.scalaArgs + ++ List("-script", settings.targetScript) + ++ settings.scriptArgs + scripting.Main.main(properArgs.toArray) case ExecuteMode.Guess => if settings.modeShouldBePossibleRun then run(settings.withExecuteMode(ExecuteMode.PossibleRun)) diff --git a/compiler/test/dotty/tools/scripting/BashScriptsTests.scala b/compiler/test/dotty/tools/scripting/BashScriptsTests.scala index a652ba8a5a43..a9b5b7198634 100644 --- a/compiler/test/dotty/tools/scripting/BashScriptsTests.scala +++ b/compiler/test/dotty/tools/scripting/BashScriptsTests.scala @@ -61,7 +61,7 @@ class BashScriptsTests: /* verify `dist/bin/scala` */ @Test def verifyScalaArgs = - val commandline = (Seq(scalaPath, showArgsScript) ++ testScriptArgs).mkString(" ") + val commandline = (Seq("SCALA_OPTS= ",scalaPath, showArgsScript) ++ testScriptArgs).mkString(" ") if bashPath.toFile.exists then var cmd = Array(bashExe, "-c", commandline) val output = for { From c9f21b84972f41792c25fad0fab5ffb4afdf006a Mon Sep 17 00:00:00 2001 From: Phil Date: Fri, 24 Sep 2021 14:59:46 -0600 Subject: [PATCH 9/9] removed platform-dependency in unit test; pass scriptArgs to precompiler jar --- .../src/dotty/tools/MainGenericRunner.scala | 31 +++++++++---------- .../tools/scripting/BashScriptsTests.scala | 16 +++++----- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index c0831cfc2010..fa6faa7d570e 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -105,7 +105,7 @@ object MainGenericRunner { case "-run" :: fqName :: tail => process(tail, settings.withExecuteMode(ExecuteMode.Run).withTargetToRun(fqName)) case ("-cp" | "-classpath" | "--class-path") :: cp :: tail => - val globdir = cp.replaceAll("[\\/][^\\/]*$","") // slash/backslash agnostic + val globdir = cp.replaceAll("[\\/][^\\/]*$", "") // slash/backslash agnostic val (tailargs, cpstr) = if globdir.nonEmpty && classpathSeparator != ";" || cp.contains(classpathSeparator) then (tail, cp) else @@ -201,24 +201,21 @@ object MainGenericRunner { } errorFn("", res) case ExecuteMode.Script => - val targetScript = Paths.get(settings.targetScript) - val targetJar = settings.targetScript.replaceAll("[.][^\\/]*$","")+".jar" - val precompiledJar = Paths.get(targetJar) - def mainClass = Jar(targetJar).mainClass match - case Some(mc) => - mc - case None => - "" - if precompiledJar.toFile.isFile && mainClass.nonEmpty && precompiledJar.toFile.lastModified >= targetScript.toFile.lastModified then - // precompiledJar is newer than targetScript - sys.props("script.path") = targetScript.toAbsolutePath.normalize.toString + val targetScript = Paths.get(settings.targetScript).toFile + val targetJar = settings.targetScript.replaceAll("[.][^\\/]*$", "")+".jar" + val precompiledJar = Paths.get(targetJar).toFile + def mainClass = Jar(targetJar).mainClass.getOrElse("") // throws exception if file not found + val jarIsValid = precompiledJar.isFile && mainClass.nonEmpty && precompiledJar.lastModified >= targetScript.lastModified + if jarIsValid then + // precompiledJar exists, is newer than targetScript, and manifest defines a mainClass + sys.props("script.path") = targetScript.toPath.toAbsolutePath.normalize.toString val scalaClasspath = ClasspathFromClassloader(Thread.currentThread().getContextClassLoader).split(classpathSeparator) val newClasspath = (settings.classPath.flatMap(_.split(classpathSeparator).filter(_.nonEmpty)) ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) - Jar(targetJar).mainClass match - case Some(mc) => - ObjectRunner.runAndCatch(newClasspath :+ File(targetJar).toURI.toURL, mc, settings.residualArgs) - case None => - Some(IllegalArgumentException(s"No main class defined in manifest in jar: $precompiledJar")) + val mc = mainClass + if mc.nonEmpty then + ObjectRunner.runAndCatch(newClasspath :+ File(targetJar).toURI.toURL, mc, settings.scriptArgs) + else + Some(IllegalArgumentException(s"No main class defined in manifest in jar: $precompiledJar")) else val properArgs = List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) diff --git a/compiler/test/dotty/tools/scripting/BashScriptsTests.scala b/compiler/test/dotty/tools/scripting/BashScriptsTests.scala index e5c149a0c4ec..8a6c6aad1ec1 100644 --- a/compiler/test/dotty/tools/scripting/BashScriptsTests.scala +++ b/compiler/test/dotty/tools/scripting/BashScriptsTests.scala @@ -58,7 +58,7 @@ class BashScriptsTests: /* verify `dist/bin/scala` non-interference with command line args following script name */ @Test def verifyScalaArgs = - val commandline = (Seq("SCALA_OPTS= ",scalaPath, showArgsScript) ++ testScriptArgs).mkString(" ") + val commandline = (Seq("SCALA_OPTS= ", scalaPath, showArgsScript) ++ testScriptArgs).mkString(" ") val (validTest, exitCode, stdout, stderr) = bashCommand(commandline) if validTest then var fail = false @@ -78,7 +78,7 @@ class BashScriptsTests: */ @Test def verifyScriptPathProperty = val scriptFile = testFiles.find(_.getName == "scriptPath.sc").get - val expected = s"/${scriptFile.getName}" + val expected = s"${scriptFile.getName}" printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName) printf("calling scriptFile: %s\n", scriptFile) val (validTest, exitCode, stdout, stderr) = bashCommand(scriptFile.absPath) @@ -105,7 +105,7 @@ class BashScriptsTests: if valid then printf(s"\n===> success: classpath begins with %s, as reported by [%s]\n", workingDirectory, scriptFile.getName) assert(valid, s"script ${scriptFile.absPath} did not report valid java.class.path first entry") - def existingPath: String = envOrElse("PATH","").norm + def existingPath: String = envOrElse("PATH", "").norm def adjustedPath = s"$javaHome/bin$psep$scalaHome/bin$psep$existingPath" def pathEntries = adjustedPath.split(psep).toList @@ -120,7 +120,7 @@ class BashScriptsTests: def fixHome(s: String): String = s.startsWith("~") match { case false => s - case true => s.replaceFirst("~",userHome) + case true => s.replaceFirst("~", userHome) } extension(s: String) { @@ -146,7 +146,7 @@ class BashScriptsTests: def absPath: String = f.getAbsolutePath.norm } - lazy val psep: String = propOrElse("path.separator","") + lazy val psep: String = propOrElse("path.separator", "") lazy val osname = propOrElse("os.name", "").toLowerCase lazy val scalacPath = s"$workingDirectory/dist/target/pack/bin/scalac".norm @@ -163,7 +163,7 @@ class BashScriptsTests: // else, SCALA_HOME if defined // else, not defined lazy val scalaHome = - if scalacPath.isFile then scalacPath.replaceAll("/bin/scalac","") + if scalacPath.isFile then scalacPath.replaceAll("/bin/scalac", "") else envOrElse("SCALA_HOME", "").norm lazy val javaHome = envOrElse("JAVA_HOME", "").norm @@ -172,7 +172,7 @@ class BashScriptsTests: ("JAVA_HOME", javaHome), ("SCALA_HOME", scalaHome), ("PATH", adjustedPath), - ).filter { case (name,valu) => valu.nonEmpty } + ).filter { case (name, valu) => valu.nonEmpty } lazy val whichBash: String = var whichBash = "" @@ -183,7 +183,7 @@ class BashScriptsTests: whichBash - def bashCommand(cmdstr: String, additionalEnvPairs:List[(String, String)] = Nil): (Boolean, Int, Seq[String], Seq[String]) = { + def bashCommand(cmdstr: String, additionalEnvPairs: List[(String, String)] = Nil): (Boolean, Int, Seq[String], Seq[String]) = { var (stdout, stderr) = (List.empty[String], List.empty[String]) if bashExe.toFile.exists then val cmd = Seq(bashExe, "-c", cmdstr)