diff --git a/compiler/test-resources/scripting/scriptPath.sc b/compiler/test-resources/scripting/scriptPath.sc index 49ed65a76515..a73064431319 100755 --- a/compiler/test-resources/scripting/scriptPath.sc +++ b/compiler/test-resources/scripting/scriptPath.sc @@ -2,9 +2,18 @@ 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") + + Option(sys.props("script.path")) match { case Some(path) => - printf("script.path: %s\n",path) - assert(path.endsWith("scriptPath.sc"),s"actual path [$path]") + if ! path.endsWith("scriptPath.sc") then + printf( s"incorrect script.path defined as [$path]") + else + printf("script.path: %s\n",path) // report the value + case None => + printf("no script.path property is defined\n") + // report relevant environment factors that might explain the error + val psep: String = Option(sys.props("path.separator")).get + val pathEntries = System.getenv("PATH").split(psep).toList + System.err.printf("sun.java.command: %s\n", sys.props("sun.java.command")) + System.err.printf("first 5 PATH entries:\n%s\n",pathEntries.take(5).mkString("\n")) } diff --git a/compiler/test/dotty/tools/scripting/BashScriptsTests.scala b/compiler/test/dotty/tools/scripting/BashScriptsTests.scala index 4c0c17ec6cd1..a4c00ee7af49 100644 --- a/compiler/test/dotty/tools/scripting/BashScriptsTests.scala +++ b/compiler/test/dotty/tools/scripting/BashScriptsTests.scala @@ -10,6 +10,7 @@ import org.junit.Test import vulpix.TestConfiguration +import dotty.tools.dotc.config.Properties._ /** Verifies correct handling of command line arguments by `dist/bin/scala` and `dist/bin/scalac`. * +. arguments following a script path must be treated as script arguments @@ -19,6 +20,13 @@ class BashScriptsTests: // classpath tests managed by scripting.ClasspathTests.scala def testFiles = scripts("/scripting") + printf("osname[%s]\n", osname) + printf("using JAVA_HOME=%s\n", javaHome) + printf("using SCALA_HOME=%s\n", scalaHome) + printf("first 5 PATH entries:\n%s\n", pathEntries.take(5).mkString("\n")) + printf("scala path: [%s]\n", scalaPath) + printf("scalac path: [%s]\n", scalacPath) + lazy val expectedOutput = List( "arg 0:[a]", "arg 1:[b]", @@ -31,65 +39,52 @@ class BashScriptsTests: lazy val testScriptArgs = Seq( "a", "b", "c", "-repl", "-run", "-script", "-debug" ) - lazy val (bashExe, bashPath) = - val bexe = getBashPath - val bpath = Paths.get(bexe) - // printf("bashExe: [%s]\n", bexe) - (bexe, bpath) - val showArgsScript = testFiles.find(_.getName == "showArgs.sc").get.absPath - val scalacPath = "dist/target/pack/bin/scalac" // which("scalac") - val scalaPath = "dist/target/pack/bin/scala" // which("scala") - - /* verify `dist/bin/scalac` */ + /* verify `dist/bin/scalac` non-interference with command line args following script name */ @Test def verifyScalacArgs = - printf("scalacPath[%s]\n", scalacPath) val commandline = (Seq(scalacPath, "-script", showArgsScript) ++ testScriptArgs).mkString(" ") - if bashPath.toFile.exists then - var cmd = Array(bashExe, "-c", commandline) - val output = Process(cmd).lazyLines_! + val (validTest, exitCode, stdout, stderr) = bashCommand(commandline) + if validTest then var fail = false printf("\n") - for (line, expect) <- output zip expectedOutput do + for (line, expect) <- stdout zip expectedOutput do printf("expected: %-17s\nactual : %s\n", expect, line) if line != expect then fail = true if fail then - assert(output == expectedOutput) + assert(stdout == expectedOutput) - /* verify `dist/bin/scala` */ + /* verify `dist/bin/scala` non-interference with command line args following script name */ @Test def verifyScalaArgs = val commandline = (Seq(scalaPath, showArgsScript) ++ testScriptArgs).mkString(" ") - if bashPath.toFile.exists then - var cmd = Array(bashExe, "-c", commandline) - val output = for { - line <- Process(cmd).lazyLines_! - } yield line + val (validTest, exitCode, stdout, stderr) = bashCommand(commandline) + if validTest then var fail = false printf("\n") var mismatches = List.empty[(String, String)] - for (line, expect) <- output zip expectedOutput do + for (line, expect) <- stdout zip expectedOutput do printf("expected: %-17s\nactual : %s\n", expect, line) if line != expect then fail = true if fail then - assert(output == expectedOutput) + assert(stdout == expectedOutput) /* - * verify that scriptPath.sc sees a valid script.path property. + * verify that scriptPath.sc sees a valid script.path property, + * and that it's value is the path to "scriptPath.sc". */ @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) - 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", _) } + printf("calling scriptFile: %s\n", scriptFile) + val (validTest, exitCode, stdout, stderr) = bashCommand(scriptFile.absPath) + if validTest then + stdout.foreach { printf("stdout: [%s]\n", _) } + stderr.foreach { printf("stderr: [%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,41 +94,87 @@ 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) - val argsfile = createArgsFile() // avoid problems caused by drive letter + printf("===> verify SCALA_OPTS='@argsfile' is properly handled by `dist/bin/scala`\n") val envPairs = List(("SCALA_OPTS", s"@$argsfile")) - val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath, envPairs:_*) - 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 (validTest, exitCode, stdout, stderr) = bashCommand(scriptFile.absPath, envPairs) + if validTest then + val expected = s"${workingDirectory.toString}" val List(line1: String, line2: String) = stdout.take(2) val valid = line2.dropWhile( _ != ' ').trim.startsWith(expected) - if valid then printf(s"\n===> success: classpath begins with %s, as reported by [%s]\n", cwd, scriptFile.getName) + 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") - lazy val cwd = Paths.get(dotty.tools.dotc.config.Properties.userDir).toFile + def existingPath: String = envOrElse("PATH","").norm + def adjustedPath = s"$javaHome/bin$psep$scalaHome/bin$psep$existingPath" + def pathEntries = adjustedPath.split(psep).toList + lazy val argsfile = createArgsFile() // avoid problems caused by drive letter def createArgsFile(): String = val utfCharset = java.nio.charset.StandardCharsets.UTF_8.name - val text = s"-classpath ${cwd.absPath}" val path = Files.createTempFile("scriptingTest", ".args") + val text = s"-classpath ${workingDirectory.absPath}" Files.write(path, text.getBytes(utfCharset)) path.toFile.getAbsolutePath.replace('\\', '/') - extension (str: String) def dropExtension: String = - str.reverse.dropWhile(_ != '.').drop(1).reverse + def fixHome(s: String): String = + s.startsWith("~") match { + case false => s + case true => s.replaceFirst("~",userHome) + } + + extension(s: String) { + def toPath: Path = Paths.get(fixHome(s)) // .toAbsolutePath + def toFile: File = s.toPath.toFile + def absPath: String = s.toFile.absPath + def norm: String = s.replace('\\', '/') // bash expects forward slash + def isFile: Boolean = s.toFile.isFile + def exists: Boolean = s.toPath.toFile.exists + def name: String = s.toFile.getName + def dropExtension: String = s.reverse.dropWhile(_ != '.').drop(1).reverse + } + + extension(p: Path) { + def listFiles: Seq[File] = p.toFile.listFiles.toList + def norm: String = p.normalize.toString.replace('\\', '/') + def name: String = p.toFile.getName + } + + extension(f: File) { + def name = f.getName + def norm: String = f.toPath.normalize.norm + def absPath: String = f.getAbsolutePath.norm + } + + 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 + lazy val scalaPath = s"$workingDirectory/dist/target/pack/bin/scala".norm - extension(f: File) def absPath: String = - f.getAbsolutePath.replace('\\', '/') + // use optional working directory TEST_CWD, if defined + lazy val workingDirectory: String = envOrElse("TEST_CWD", userDir) - lazy val osname = Option(sys.props("os.name")).getOrElse("").toLowerCase + // use optional TEST_BASH if defined, otherwise, bash must be in PATH + lazy val bashExe: String = envOrElse("TEST_BASH", whichBash) - def getBashPath: String = + // test env SCALA_HOME is: + // dist/target/pack, if present + // else, SCALA_HOME if defined + // else, not defined + lazy val scalaHome = + if scalacPath.isFile then scalacPath.replaceAll("/bin/scalac","") + else envOrElse("SCALA_HOME", "").norm + + lazy val javaHome = envOrElse("JAVA_HOME", "").norm + + lazy val testEnvPairs = List( + ("JAVA_HOME", javaHome), + ("SCALA_HOME", scalaHome), + ("PATH", adjustedPath), + ).filter { case (name,valu) => valu.nonEmpty } + + lazy val whichBash: String = var whichBash = "" - //printf("osname[%s]\n", osname) if osname.startsWith("windows") then whichBash = which("bash.exe") else @@ -141,16 +182,23 @@ class BashScriptsTests: whichBash - def bashCommand(cmdstr: String, envPairs: (String, String)*): (Int, Seq[String], Seq[String]) = { - import scala.sys.process._ - val cmd = Seq(bashExe, "-c", cmdstr) - val proc = Process(cmd, None, envPairs *) + def bashCommand(cmdstr: String, additionalEnvPairs:List[(String, String)] = Nil): (Boolean, Int, Seq[String], Seq[String]) = { var (stdout, stderr) = (List.empty[String], List.empty[String]) - val exitVal = proc ! ProcessLogger ( - (out: String) => stdout ::= out, - (err: String) => stderr ::= err - ) - (exitVal, stdout.reverse, stderr.reverse) + if bashExe.toFile.exists then + val cmd = Seq(bashExe, "-c", cmdstr) + val envPairs = testEnvPairs ++ additionalEnvPairs + val proc = Process(cmd, None, envPairs *) + val exitVal = proc ! ProcessLogger ( + (out: String) => stdout ::= out, + (err: String) => stderr ::= err + ) + val validTest = exitVal == 0 && ! stderr.exists(_.contains("Permission denied")) + if ! validTest then + printf("\nunable to execute script, return value is %d\n", exitVal) + stderr.foreach { System.err.printf("stderr [%s]\n", _) } + (validTest, exitVal, stdout.reverse, stderr.reverse) + else + (false, -1, Nil, Nil) } def execCmd(command: String, options: String *): Seq[String] =