Skip to content

Commit 4a875e5

Browse files
committed
additional support to fix 12962
1 parent 918705d commit 4a875e5

File tree

2 files changed

+119
-67
lines changed

2 files changed

+119
-67
lines changed

compiler/test-resources/scripting/scriptPath.sc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@
22

33
def main(args: Array[String]): Unit =
44
args.zipWithIndex.foreach { case (arg,i) => printf("arg %d: [%s]\n",i,arg) }
5-
val path = Option(sys.props("script.path")) match {
6-
case None => printf("no script.path property is defined\n")
5+
6+
Option(sys.props("script.path")) match {
77
case Some(path) =>
8-
printf("script.path: %s\n",path)
9-
assert(path.endsWith("scriptPath.sc"),s"actual path [$path]")
8+
if ! path.endsWith("scriptPath.sc") then
9+
printf( s"incorrect script.path defined as [$path]")
10+
else
11+
printf("script.path: %s\n",path) // report the value
12+
case None =>
13+
printf("no script.path property is defined\n")
14+
// report relevant environment factors that might explain the error
15+
val psep: String = Option(sys.props("path.separator")).get
16+
val pathEntries = System.getenv("PATH").split(psep).toList
17+
System.err.printf("sun.java.command: %s\n", sys.props("sun.java.command"))
18+
System.err.printf("first 5 PATH entries:\n%s\n",pathEntries.take(5).mkString("\n"))
1019
}

compiler/test/dotty/tools/scripting/BashScriptsTests.scala

Lines changed: 106 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.junit.Test
1010

1111
import vulpix.TestConfiguration
1212

13+
import dotty.tools.dotc.config.Properties._
1314

1415
/** Verifies correct handling of command line arguments by `dist/bin/scala` and `dist/bin/scalac`.
1516
* +. arguments following a script path must be treated as script arguments
@@ -19,6 +20,13 @@ class BashScriptsTests:
1920
// classpath tests managed by scripting.ClasspathTests.scala
2021
def testFiles = scripts("/scripting")
2122

23+
printf("osname[%s]\n", osname)
24+
printf("using JAVA_HOME=%s\n", javaHome)
25+
printf("using SCALA_HOME=%s\n", scalaHome)
26+
printf("first 5 PATH entries:\n%s\n", pathEntries.take(5).mkString("\n"))
27+
printf("scala path: [%s]\n", scalaPath)
28+
printf("scalac path: [%s]\n", scalacPath)
29+
2230
lazy val expectedOutput = List(
2331
"arg 0:[a]",
2432
"arg 1:[b]",
@@ -31,70 +39,52 @@ class BashScriptsTests:
3139
lazy val testScriptArgs = Seq(
3240
"a", "b", "c", "-repl", "-run", "-script", "-debug"
3341
)
34-
lazy val (bashExe, bashPath) =
35-
val bexe = getBashPath
36-
val bpath = Paths.get(bexe)
37-
// printf("bashExe: [%s]\n", bexe)
38-
(bexe, bpath)
39-
4042
val showArgsScript = testFiles.find(_.getName == "showArgs.sc").get.absPath
4143

42-
val scalacPath = "dist/target/pack/bin/scalac" // which("scalac")
43-
val scalaPath = "dist/target/pack/bin/scala" // which("scala")
44-
45-
def isFile(path: String): Boolean =
46-
Files.isRegularFile(Paths.get(path))
47-
48-
/* verify `dist/bin/scalac` */
44+
/* verify `dist/bin/scalac` non-interference with command line args following script name */
4945
@Test def verifyScalacArgs =
50-
assert(isFile(scalacPath))
51-
printf("scalacPath[%s]\n",scalacPath)
5246
val commandline = (Seq(scalacPath, "-script", showArgsScript) ++ testScriptArgs).mkString(" ")
53-
if bashPath.toFile.exists then
54-
var cmd = Array(bashExe, "-c", commandline)
55-
val output = Process(cmd).lazyLines_!
47+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline)
48+
if validTest then
5649
var fail = false
5750
printf("\n")
58-
for (line, expect) <- output zip expectedOutput do
51+
for (line, expect) <- stdout zip expectedOutput do
5952
printf("expected: %-17s\nactual : %s\n", expect, line)
6053
if line != expect then
6154
fail = true
6255

6356
if fail then
64-
assert(output == expectedOutput)
57+
assert(stdout == expectedOutput)
6558

66-
/* verify `dist/bin/scala` */
59+
/* verify `dist/bin/scala` non-interference with command line args following script name */
6760
@Test def verifyScalaArgs =
68-
assert(isFile(scalaPath))
6961
val commandline = (Seq(scalaPath, showArgsScript) ++ testScriptArgs).mkString(" ")
70-
if bashPath.toFile.exists then
71-
var cmd = Array(bashExe, "-c", commandline)
72-
val output = for {
73-
line <- Process(cmd).lazyLines_!
74-
} yield line
62+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline)
63+
if validTest then
7564
var fail = false
7665
printf("\n")
7766
var mismatches = List.empty[(String, String)]
78-
for (line, expect) <- output zip expectedOutput do
67+
for (line, expect) <- stdout zip expectedOutput do
7968
printf("expected: %-17s\nactual : %s\n", expect, line)
8069
if line != expect then
8170
fail = true
8271

8372
if fail then
84-
assert(output == expectedOutput)
73+
assert(stdout == expectedOutput)
8574

8675
/*
87-
* verify that scriptPath.sc sees a valid script.path property.
76+
* verify that scriptPath.sc sees a valid script.path property,
77+
* and that it's value is the path to "scriptPath.sc".
8878
*/
8979
@Test def verifyScriptPathProperty =
9080
val scriptFile = testFiles.find(_.getName == "scriptPath.sc").get
9181
val expected = s"/${scriptFile.getName}"
9282
printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName)
93-
val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath)
94-
if exitCode == 0 && ! stderr.exists(_.contains("Permission denied")) then
95-
// var cmd = Array(bashExe, "-c", scriptFile.absPath)
96-
// val stdout = Process(cmd).lazyLines_!
97-
stdout.foreach { printf("######### [%s]\n", _) }
83+
printf("calling scriptFile: %s\n", scriptFile)
84+
val (validTest, exitCode, stdout, stderr) = bashCommand(scriptFile.absPath)
85+
if validTest then
86+
stdout.foreach { printf("stdout: [%s]\n", _) }
87+
stderr.foreach { printf("stderr: [%s]\n", _) }
9888
val valid = stdout.exists { _.endsWith(expected) }
9989
if valid then printf("# valid script.path reported by [%s]\n", scriptFile.getName)
10090
assert(valid, s"script ${scriptFile.absPath} did not report valid script.path value")
@@ -104,58 +94,111 @@ class BashScriptsTests:
10494
*/
10595
@Test def verifyScalaOpts =
10696
val scriptFile = testFiles.find(_.getName == "classpathReport.sc").get
107-
printf("===> verify valid system property script.path is reported by script [%s]\n", scriptFile.getName)
108-
val argsfile = createArgsFile() // avoid problems caused by drive letter
97+
printf("===> verify SCALA_OPTS='@argsfile' is properly handled by `dist/bin/scala`\n")
10998
val envPairs = List(("SCALA_OPTS", s"@$argsfile"))
110-
val (exitCode, stdout, stderr) = bashCommand(scriptFile.absPath, envPairs:_*)
111-
if exitCode != 0 || stderr.exists(_.contains("Permission denied")) then
112-
stderr.foreach { System.err.printf("stderr [%s]\n", _) }
113-
printf("unable to execute script, return value is %d\n", exitCode)
114-
else
115-
// val stdout: Seq[String] = Process(cmd, cwd, envPairs:_*).lazyLines_!.toList
116-
val expected = s"${cwd.toString}"
99+
val (validTest, exitCode, stdout, stderr) = bashCommand(scriptFile.absPath, envPairs)
100+
if validTest then
101+
val expected = s"${workingDirectory.toString}"
117102
val List(line1: String, line2: String) = stdout.take(2)
118103
val valid = line2.dropWhile( _ != ' ').trim.startsWith(expected)
119-
if valid then printf(s"\n===> success: classpath begins with %s, as reported by [%s]\n", cwd, scriptFile.getName)
104+
if valid then printf(s"\n===> success: classpath begins with %s, as reported by [%s]\n", workingDirectory, scriptFile.getName)
120105
assert(valid, s"script ${scriptFile.absPath} did not report valid java.class.path first entry")
121106

122-
lazy val cwd = Paths.get(dotty.tools.dotc.config.Properties.userDir).toFile
107+
def existingPath: String = envOrElse("PATH","").norm
108+
def adjustedPath = s"$javaHome/bin$psep$scalaHome/bin$psep$existingPath"
109+
def pathEntries = adjustedPath.split(psep).toList
123110

111+
lazy val argsfile = createArgsFile() // avoid problems caused by drive letter
124112
def createArgsFile(): String =
125113
val utfCharset = java.nio.charset.StandardCharsets.UTF_8.name
126-
val text = s"-classpath ${cwd.absPath}"
127114
val path = Files.createTempFile("scriptingTest", ".args")
115+
val text = s"-classpath ${workingDirectory.absPath}"
128116
Files.write(path, text.getBytes(utfCharset))
129117
path.toFile.getAbsolutePath.replace('\\', '/')
130118

131-
extension (str: String) def dropExtension: String =
132-
str.reverse.dropWhile(_ != '.').drop(1).reverse
119+
def fixHome(s: String): String =
120+
s.startsWith("~") match {
121+
case false => s
122+
case true => s.replaceFirst("~",userHome)
123+
}
124+
125+
extension(s: String) {
126+
def toPath: Path = Paths.get(fixHome(s)) // .toAbsolutePath
127+
def toFile: File = s.toPath.toFile
128+
def absPath: String = s.toFile.absPath
129+
def norm: String = s.replace('\\', '/') // bash expects forward slash
130+
def isFile: Boolean = s.toFile.isFile
131+
def exists: Boolean = s.toPath.toFile.exists
132+
def name: String = s.toFile.getName
133+
def dropExtension: String = s.reverse.dropWhile(_ != '.').drop(1).reverse
134+
}
133135

134-
extension(f: File) def absPath: String =
135-
f.getAbsolutePath.replace('\\', '/')
136+
extension(p: Path) {
137+
def listFiles: Seq[File] = p.toFile.listFiles.toList
138+
def norm: String = p.normalize.toString.replace('\\', '/')
139+
def name: String = p.toFile.getName
140+
}
136141

137-
lazy val osname = Option(sys.props("os.name")).getOrElse("").toLowerCase
142+
extension(f: File) {
143+
def name = f.getName
144+
def norm: String = f.toPath.normalize.norm
145+
def absPath: String = f.getAbsolutePath.norm
146+
}
138147

139-
def getBashPath: String =
148+
lazy val psep: String = propOrElse("path.separator","")
149+
lazy val osname = propOrElse("os.name", "").toLowerCase
150+
151+
lazy val scalacPath = s"$workingDirectory/dist/target/pack/bin/scalac".norm
152+
lazy val scalaPath = s"$workingDirectory/dist/target/pack/bin/scala".norm
153+
154+
// use optional working directory TEST_CWD, if defined
155+
lazy val workingDirectory: String = envOrElse("TEST_CWD", userDir)
156+
157+
// use optional TEST_BASH if defined, otherwise, bash must be in PATH
158+
lazy val bashExe: String = envOrElse("TEST_BASH", whichBash)
159+
160+
// test env SCALA_HOME is:
161+
// dist/target/pack, if present
162+
// else, SCALA_HOME if defined
163+
// else, not defined
164+
lazy val scalaHome =
165+
if scalacPath.isFile then scalacPath.replaceAll("/bin/scalac","")
166+
else envOrElse("SCALA_HOME", "").norm
167+
168+
lazy val javaHome = envOrElse("JAVA_HOME", "").norm
169+
170+
lazy val testEnvPairs = List(
171+
("JAVA_HOME", javaHome),
172+
("SCALA_HOME", scalaHome),
173+
("PATH", adjustedPath),
174+
).filter { case (name,valu) => valu.nonEmpty }
175+
176+
lazy val whichBash: String =
140177
var whichBash = ""
141-
//printf("osname[%s]\n", osname)
142178
if osname.startsWith("windows") then
143179
whichBash = which("bash.exe")
144180
else
145181
whichBash = which("bash")
146182

147183
whichBash
148184

149-
def bashCommand(cmdstr: String, envPairs: (String, String)*): (Int, Seq[String], Seq[String]) = {
150-
import scala.sys.process._
151-
val cmd = Seq(bashExe, "-c", cmdstr)
152-
val proc = Process(cmd, None, envPairs *)
185+
def bashCommand(cmdstr: String, additionalEnvPairs:List[(String, String)] = Nil): (Boolean, Int, Seq[String], Seq[String]) = {
153186
var (stdout, stderr) = (List.empty[String], List.empty[String])
154-
val exitVal = proc ! ProcessLogger (
155-
(out: String) => stdout ::= out,
156-
(err: String) => stderr ::= err
157-
)
158-
(exitVal, stdout.reverse, stderr.reverse)
187+
if bashExe.toFile.exists then
188+
val cmd = Seq(bashExe, "-c", cmdstr)
189+
val envPairs = testEnvPairs ++ additionalEnvPairs
190+
val proc = Process(cmd, None, envPairs *)
191+
val exitVal = proc ! ProcessLogger (
192+
(out: String) => stdout ::= out,
193+
(err: String) => stderr ::= err
194+
)
195+
val validTest = exitVal == 0 && ! stderr.exists(_.contains("Permission denied"))
196+
if ! validTest then
197+
printf("\nunable to execute script, return value is %d\n", exitVal)
198+
stderr.foreach { System.err.printf("stderr [%s]\n", _) }
199+
(validTest, exitVal, stdout.reverse, stderr.reverse)
200+
else
201+
(false, -1, Nil, Nil)
159202
}
160203

161204
def execCmd(command: String, options: String *): Seq[String] =

0 commit comments

Comments
 (0)